Precise DOM morphing
morphing typescript dom

Remove semi

+1766 -4231
+12 -11
.prettierrc
··· 1 1 { 2 - "printWidth": 130, 3 - "useTabs": true, 4 - "overrides": [ 5 - { 6 - "files": "*.md", 7 - "options": { 8 - "useTabs": false, 9 - "tabWidth": 2 10 - } 11 - } 12 - ] 2 + "printWidth": 130, 3 + "semi": false, 4 + "useTabs": true, 5 + "overrides": [ 6 + { 7 + "files": "*.md", 8 + "options": { 9 + "useTabs": false, 10 + "tabWidth": 2 11 + } 12 + } 13 + ] 13 14 }
+5 -5
README.md
··· 24 24 25 25 ```html 26 26 <script type="module"> 27 - import { morph } from "https://www.unpkg.com/morphlex@0.0.16/dist/morphlex.min.js"; 27 + import { morph } from "https://www.unpkg.com/morphlex@0.0.16/dist/morphlex.min.js" 28 28 29 - morph(currentNode, referenceNode); 30 - morphInner(currentNode, referenceNode); 29 + morph(currentNode, referenceNode) 30 + morphInner(currentNode, referenceNode) 31 31 </script> 32 32 ``` 33 33 ··· 38 38 ``` 39 39 40 40 ```javascript 41 - import { morph } from "morphlex"; 41 + import { morph } from "morphlex" 42 42 43 - morph(currentNode, referenceNode); 43 + morph(currentNode, referenceNode) 44 44 ``` 45 45 46 46 The `currentNode` will be morphed into the state of the `referenceNode`. The `referenceNode` will not be mutated in this process.
-224
coverage/base.css
··· 1 - body, html { 2 - margin:0; padding: 0; 3 - height: 100%; 4 - } 5 - body { 6 - font-family: Helvetica Neue, Helvetica, Arial; 7 - font-size: 14px; 8 - color:#333; 9 - } 10 - .small { font-size: 12px; } 11 - *, *:after, *:before { 12 - -webkit-box-sizing:border-box; 13 - -moz-box-sizing:border-box; 14 - box-sizing:border-box; 15 - } 16 - h1 { font-size: 20px; margin: 0;} 17 - h2 { font-size: 14px; } 18 - pre { 19 - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 - margin: 0; 21 - padding: 0; 22 - -moz-tab-size: 2; 23 - -o-tab-size: 2; 24 - tab-size: 2; 25 - } 26 - a { color:#0074D9; text-decoration:none; } 27 - a:hover { text-decoration:underline; } 28 - .strong { font-weight: bold; } 29 - .space-top1 { padding: 10px 0 0 0; } 30 - .pad2y { padding: 20px 0; } 31 - .pad1y { padding: 10px 0; } 32 - .pad2x { padding: 0 20px; } 33 - .pad2 { padding: 20px; } 34 - .pad1 { padding: 10px; } 35 - .space-left2 { padding-left:55px; } 36 - .space-right2 { padding-right:20px; } 37 - .center { text-align:center; } 38 - .clearfix { display:block; } 39 - .clearfix:after { 40 - content:''; 41 - display:block; 42 - height:0; 43 - clear:both; 44 - visibility:hidden; 45 - } 46 - .fl { float: left; } 47 - @media only screen and (max-width:640px) { 48 - .col3 { width:100%; max-width:100%; } 49 - .hide-mobile { display:none!important; } 50 - } 51 - 52 - .quiet { 53 - color: #7f7f7f; 54 - color: rgba(0,0,0,0.5); 55 - } 56 - .quiet a { opacity: 0.7; } 57 - 58 - .fraction { 59 - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 - font-size: 10px; 61 - color: #555; 62 - background: #E8E8E8; 63 - padding: 4px 5px; 64 - border-radius: 3px; 65 - vertical-align: middle; 66 - } 67 - 68 - div.path a:link, div.path a:visited { color: #333; } 69 - table.coverage { 70 - border-collapse: collapse; 71 - margin: 10px 0 0 0; 72 - padding: 0; 73 - } 74 - 75 - table.coverage td { 76 - margin: 0; 77 - padding: 0; 78 - vertical-align: top; 79 - } 80 - table.coverage td.line-count { 81 - text-align: right; 82 - padding: 0 5px 0 20px; 83 - } 84 - table.coverage td.line-coverage { 85 - text-align: right; 86 - padding-right: 10px; 87 - min-width:20px; 88 - } 89 - 90 - table.coverage td span.cline-any { 91 - display: inline-block; 92 - padding: 0 5px; 93 - width: 100%; 94 - } 95 - .missing-if-branch { 96 - display: inline-block; 97 - margin-right: 5px; 98 - border-radius: 3px; 99 - position: relative; 100 - padding: 0 4px; 101 - background: #333; 102 - color: yellow; 103 - } 104 - 105 - .skip-if-branch { 106 - display: none; 107 - margin-right: 10px; 108 - position: relative; 109 - padding: 0 4px; 110 - background: #ccc; 111 - color: white; 112 - } 113 - .missing-if-branch .typ, .skip-if-branch .typ { 114 - color: inherit !important; 115 - } 116 - .coverage-summary { 117 - border-collapse: collapse; 118 - width: 100%; 119 - } 120 - .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 - .keyline-all { border: 1px solid #ddd; } 122 - .coverage-summary td, .coverage-summary th { padding: 10px; } 123 - .coverage-summary tbody { border: 1px solid #bbb; } 124 - .coverage-summary td { border-right: 1px solid #bbb; } 125 - .coverage-summary td:last-child { border-right: none; } 126 - .coverage-summary th { 127 - text-align: left; 128 - font-weight: normal; 129 - white-space: nowrap; 130 - } 131 - .coverage-summary th.file { border-right: none !important; } 132 - .coverage-summary th.pct { } 133 - .coverage-summary th.pic, 134 - .coverage-summary th.abs, 135 - .coverage-summary td.pct, 136 - .coverage-summary td.abs { text-align: right; } 137 - .coverage-summary td.file { white-space: nowrap; } 138 - .coverage-summary td.pic { min-width: 120px !important; } 139 - .coverage-summary tfoot td { } 140 - 141 - .coverage-summary .sorter { 142 - height: 10px; 143 - width: 7px; 144 - display: inline-block; 145 - margin-left: 0.5em; 146 - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 - } 148 - .coverage-summary .sorted .sorter { 149 - background-position: 0 -20px; 150 - } 151 - .coverage-summary .sorted-desc .sorter { 152 - background-position: 0 -10px; 153 - } 154 - .status-line { height: 10px; } 155 - /* yellow */ 156 - .cbranch-no { background: yellow !important; color: #111; } 157 - /* dark red */ 158 - .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 159 - .low .chart { border:1px solid #C21F39 } 160 - .highlighted, 161 - .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ 162 - background: #C21F39 !important; 163 - } 164 - /* medium red */ 165 - .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 166 - /* light red */ 167 - .low, .cline-no { background:#FCE1E5 } 168 - /* light green */ 169 - .high, .cline-yes { background:rgb(230,245,208) } 170 - /* medium green */ 171 - .cstat-yes { background:rgb(161,215,106) } 172 - /* dark green */ 173 - .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 174 - .high .chart { border:1px solid rgb(77,146,33) } 175 - /* dark yellow (gold) */ 176 - .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 177 - .medium .chart { border:1px solid #f9cd0b; } 178 - /* light yellow */ 179 - .medium { background: #fff4c2; } 180 - 181 - .cstat-skip { background: #ddd; color: #111; } 182 - .fstat-skip { background: #ddd; color: #111 !important; } 183 - .cbranch-skip { background: #ddd !important; color: #111; } 184 - 185 - span.cline-neutral { background: #eaeaea; } 186 - 187 - .coverage-summary td.empty { 188 - opacity: .5; 189 - padding-top: 4px; 190 - padding-bottom: 4px; 191 - line-height: 1; 192 - color: #888; 193 - } 194 - 195 - .cover-fill, .cover-empty { 196 - display:inline-block; 197 - height: 12px; 198 - } 199 - .chart { 200 - line-height: 0; 201 - } 202 - .cover-empty { 203 - background: white; 204 - } 205 - .cover-full { 206 - border-right: none !important; 207 - } 208 - pre.prettyprint { 209 - border: none !important; 210 - padding: 0 !important; 211 - margin: 0 !important; 212 - } 213 - .com { color: #999 !important; } 214 - .ignore-none { color: #999; font-weight: normal; } 215 - 216 - .wrapper { 217 - min-height: 100%; 218 - height: auto !important; 219 - height: 100%; 220 - margin: 0 auto -48px; 221 - } 222 - .footer, .push { 223 - height: 48px; 224 - }
-87
coverage/block-navigation.js
··· 1 - /* eslint-disable */ 2 - var jumpToCode = (function init() { 3 - // Classes of code we would like to highlight in the file view 4 - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 - 6 - // Elements to highlight in the file listing view 7 - var fileListingElements = ['td.pct.low']; 8 - 9 - // We don't want to select elements that are direct descendants of another match 10 - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 - 12 - // Selector that finds elements on the page to which we can jump 13 - var selector = 14 - fileListingElements.join(', ') + 15 - ', ' + 16 - notSelector + 17 - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 - 19 - // The NodeList of matching elements 20 - var missingCoverageElements = document.querySelectorAll(selector); 21 - 22 - var currentIndex; 23 - 24 - function toggleClass(index) { 25 - missingCoverageElements 26 - .item(currentIndex) 27 - .classList.remove('highlighted'); 28 - missingCoverageElements.item(index).classList.add('highlighted'); 29 - } 30 - 31 - function makeCurrent(index) { 32 - toggleClass(index); 33 - currentIndex = index; 34 - missingCoverageElements.item(index).scrollIntoView({ 35 - behavior: 'smooth', 36 - block: 'center', 37 - inline: 'center' 38 - }); 39 - } 40 - 41 - function goToPrevious() { 42 - var nextIndex = 0; 43 - if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 - nextIndex = missingCoverageElements.length - 1; 45 - } else if (missingCoverageElements.length > 1) { 46 - nextIndex = currentIndex - 1; 47 - } 48 - 49 - makeCurrent(nextIndex); 50 - } 51 - 52 - function goToNext() { 53 - var nextIndex = 0; 54 - 55 - if ( 56 - typeof currentIndex === 'number' && 57 - currentIndex < missingCoverageElements.length - 1 58 - ) { 59 - nextIndex = currentIndex + 1; 60 - } 61 - 62 - makeCurrent(nextIndex); 63 - } 64 - 65 - return function jump(event) { 66 - if ( 67 - document.getElementById('fileSearch') === document.activeElement && 68 - document.activeElement != null 69 - ) { 70 - // if we're currently focused on the search input, we don't want to navigate 71 - return; 72 - } 73 - 74 - switch (event.which) { 75 - case 78: // n 76 - case 74: // j 77 - goToNext(); 78 - break; 79 - case 66: // b 80 - case 75: // k 81 - case 80: // p 82 - goToPrevious(); 83 - break; 84 - } 85 - }; 86 - })(); 87 - window.addEventListener('keydown', jumpToCode);
-215
coverage/clover.xml
··· 1 - <?xml version="1.0" encoding="UTF-8"?> 2 - <coverage generated="1761859587963" clover="3.2.0"> 3 - <project timestamp="1761859587963" name="All files"> 4 - <metrics statements="206" coveredstatements="196" conditionals="191" coveredconditionals="170" methods="37" coveredmethods="37" elements="434" coveredelements="403" complexity="0" loc="206" ncloc="206" packages="1" files="1" classes="1"/> 5 - <file name="morphlex.ts" path="/Users/joeldrapper/src/morphlex/src/morphlex.ts"> 6 - <metrics statements="206" coveredstatements="196" conditionals="191" coveredconditionals="170" methods="37" coveredmethods="37"/> 7 - <line num="53" count="95" type="cond" truecount="2" falsecount="0"/> 8 - <line num="54" count="95" type="stmt"/> 9 - <line num="58" count="7" type="cond" truecount="2" falsecount="0"/> 10 - <line num="59" count="6" type="stmt"/> 11 - <line num="63" count="1" type="stmt"/> 12 - <line num="65" count="1" type="cond" truecount="1" falsecount="1"/> 13 - <line num="66" count="1" type="stmt"/> 14 - <line num="70" count="5" type="stmt"/> 15 - <line num="71" count="5" type="stmt"/> 16 - <line num="73" count="5" type="cond" truecount="1" falsecount="1"/> 17 - <line num="74" count="0" type="stmt"/> 18 - <line num="95" count="101" type="stmt"/> 19 - <line num="96" count="101" type="stmt"/> 20 - <line num="98" count="101" type="cond" truecount="2" falsecount="0"/> 21 - <line num="99" count="101" type="cond" truecount="2" falsecount="0"/> 22 - <line num="100" count="101" type="stmt"/> 23 - <line num="101" count="101" type="stmt"/> 24 - <line num="102" count="101" type="stmt"/> 25 - <line num="103" count="101" type="stmt"/> 26 - <line num="104" count="101" type="stmt"/> 27 - <line num="105" count="101" type="stmt"/> 28 - <line num="106" count="101" type="stmt"/> 29 - <line num="107" count="101" type="stmt"/> 30 - <line num="108" count="101" type="stmt"/> 31 - <line num="109" count="101" type="stmt"/> 32 - <line num="113" count="95" type="stmt"/> 33 - <line num="114" count="95" type="cond" truecount="2" falsecount="0"/> 34 - <line num="115" count="95" type="stmt"/> 35 - <line num="120" count="6" type="stmt"/> 36 - <line num="121" count="6" type="cond" truecount="2" falsecount="0"/> 37 - <line num="122" count="5" type="stmt"/> 38 - <line num="123" count="5" type="stmt"/> 39 - <line num="125" count="1" type="stmt"/> 40 - <line num="131" count="101" type="cond" truecount="2" falsecount="0"/> 41 - <line num="132" count="100" type="stmt"/> 42 - <line num="133" count="100" type="stmt"/> 43 - <line num="134" count="100" type="stmt"/> 44 - <line num="135" count="100" type="stmt"/> 45 - <line num="136" count="1" type="stmt"/> 46 - <line num="140" count="99" type="stmt"/> 47 - <line num="141" count="99" type="stmt"/> 48 - <line num="142" count="99" type="stmt"/> 49 - <line num="146" count="99" type="stmt"/> 50 - <line num="148" count="99" type="stmt"/> 51 - <line num="149" count="99" type="stmt"/> 52 - <line num="150" count="37" type="stmt"/> 53 - <line num="151" count="37" type="stmt"/> 54 - <line num="153" count="37" type="cond" truecount="4" falsecount="0"/> 55 - <line num="154" count="29" type="stmt"/> 56 - <line num="156" count="29" type="cond" truecount="2" falsecount="0"/> 57 - <line num="157" count="29" type="cond" truecount="2" falsecount="0"/> 58 - <line num="159" count="8" type="stmt"/> 59 - <line num="161" count="8" type="cond" truecount="4" falsecount="0"/> 60 - <line num="162" count="3" type="cond" truecount="2" falsecount="0"/> 61 - <line num="163" count="3" type="cond" truecount="2" falsecount="0"/> 62 - <line num="167" count="37" type="stmt"/> 63 - <line num="168" count="37" type="stmt"/> 64 - <line num="169" count="74" type="cond" truecount="2" falsecount="0"/> 65 - <line num="170" count="74" type="cond" truecount="2" falsecount="0"/> 66 - <line num="171" count="37" type="stmt"/> 67 - <line num="178" count="198" type="stmt"/> 68 - <line num="180" count="198" type="stmt"/> 69 - <line num="181" count="198" type="stmt"/> 70 - <line num="182" count="215" type="stmt"/> 71 - <line num="183" count="215" type="stmt"/> 72 - <line num="186" count="215" type="cond" truecount="2" falsecount="0"/> 73 - <line num="188" count="213" type="stmt"/> 74 - <line num="190" count="213" type="stmt"/> 75 - <line num="191" count="823" type="stmt"/> 76 - <line num="192" count="823" type="cond" truecount="2" falsecount="0"/> 77 - <line num="193" count="823" type="cond" truecount="2" falsecount="0"/> 78 - <line num="194" count="610" type="stmt"/> 79 - <line num="201" count="184" type="cond" truecount="2" falsecount="0"/> 80 - <line num="202" count="4" type="stmt"/> 81 - <line num="206" count="180" type="stmt"/> 82 - <line num="208" count="180" type="cond" truecount="4" falsecount="0"/> 83 - <line num="210" count="179" type="cond" truecount="4" falsecount="0"/> 84 - <line num="213" count="179" type="stmt"/> 85 - <line num="215" count="179" type="stmt"/> 86 - <line num="219" count="78" type="cond" truecount="3" falsecount="1"/> 87 - <line num="221" count="78" type="cond" truecount="5" falsecount="0"/> 88 - <line num="223" count="48" type="stmt"/> 89 - <line num="224" count="30" type="stmt"/> 90 - <line num="226" count="78" type="stmt"/> 91 - <line num="230" count="184" type="stmt"/> 92 - <line num="232" count="184" type="cond" truecount="2" falsecount="0"/> 93 - <line num="234" count="2" type="stmt"/> 94 - <line num="235" count="182" type="cond" truecount="4" falsecount="0"/> 95 - <line num="239" count="3" type="stmt"/> 96 - <line num="242" count="3" type="stmt"/> 97 - <line num="243" count="3" type="stmt"/> 98 - <line num="244" count="12" type="stmt"/> 99 - <line num="245" count="12" type="stmt"/> 100 - <line num="249" count="3" type="stmt"/> 101 - <line num="250" count="13" type="stmt"/> 102 - <line num="251" count="13" type="stmt"/> 103 - <line num="252" count="13" type="stmt"/> 104 - <line num="256" count="13" type="cond" truecount="2" falsecount="0"/> 105 - <line num="260" count="11" type="stmt"/> 106 - <line num="265" count="78" type="stmt"/> 107 - <line num="266" count="88" type="cond" truecount="5" falsecount="0"/> 108 - <line num="267" count="14" type="stmt"/> 109 - <line num="268" count="14" type="stmt"/> 110 - <line num="273" count="78" type="stmt"/> 111 - <line num="274" count="83" type="stmt"/> 112 - <line num="275" count="83" type="cond" truecount="5" falsecount="0"/> 113 - <line num="276" count="19" type="stmt"/> 114 - <line num="277" count="19" type="stmt"/> 115 - <line num="283" count="78" type="cond" truecount="4" falsecount="0"/> 116 - <line num="284" count="19" type="stmt"/> 117 - <line num="285" count="19" type="stmt"/> 118 - <line num="286" count="19" type="stmt"/> 119 - <line num="287" count="19" type="cond" truecount="2" falsecount="0"/> 120 - <line num="292" count="17" type="stmt"/> 121 - <line num="294" count="59" type="cond" truecount="4" falsecount="0"/> 122 - <line num="295" count="2" type="stmt"/> 123 - <line num="296" count="57" type="cond" truecount="2" falsecount="0"/> 124 - <line num="302" count="1" type="stmt"/> 125 - <line num="304" count="1" type="stmt"/> 126 - <line num="305" count="1" type="cond" truecount="1" falsecount="1"/> 127 - <line num="311" count="123" type="stmt"/> 128 - <line num="313" count="123" type="stmt"/> 129 - <line num="314" count="123" type="stmt"/> 130 - <line num="316" count="123" type="stmt"/> 131 - <line num="317" count="182" type="stmt"/> 132 - <line num="318" count="182" type="stmt"/> 133 - <line num="320" count="182" type="cond" truecount="4" falsecount="0"/> 134 - <line num="321" count="165" type="stmt"/> 135 - <line num="323" count="165" type="cond" truecount="2" falsecount="0"/> 136 - <line num="324" count="91" type="cond" truecount="2" falsecount="0"/> 137 - <line num="325" count="1" type="stmt"/> 138 - <line num="327" count="90" type="stmt"/> 139 - <line num="329" count="74" type="stmt"/> 140 - <line num="330" count="17" type="cond" truecount="1" falsecount="1"/> 141 - <line num="331" count="17" type="stmt"/> 142 - <line num="332" count="0" type="cond" truecount="0" falsecount="2"/> 143 - <line num="333" count="0" type="stmt"/> 144 - <line num="338" count="123" type="stmt"/> 145 - <line num="339" count="113" type="stmt"/> 146 - <line num="340" count="113" type="cond" truecount="1" falsecount="1"/> 147 - <line num="345" count="90" type="cond" truecount="4" falsecount="0"/> 148 - <line num="347" count="89" type="stmt"/> 149 - <line num="350" count="89" type="cond" truecount="2" falsecount="0"/> 150 - <line num="352" count="90" type="stmt"/> 151 - <line num="353" count="90" type="stmt"/> 152 - <line num="356" count="90" type="stmt"/> 153 - <line num="357" count="121" type="cond" truecount="2" falsecount="0"/> 154 - <line num="358" count="117" type="stmt"/> 155 - <line num="360" count="117" type="cond" truecount="4" falsecount="0"/> 156 - <line num="361" count="89" type="stmt"/> 157 - <line num="364" count="117" type="cond" truecount="2" falsecount="0"/> 158 - <line num="365" count="82" type="cond" truecount="2" falsecount="0"/> 159 - <line num="366" count="54" type="stmt"/> 160 - <line num="367" count="54" type="stmt"/> 161 - <line num="369" count="28" type="stmt"/> 162 - <line num="371" count="30" type="cond" truecount="4" falsecount="0"/> 163 - <line num="372" count="1" type="stmt"/> 164 - <line num="373" count="1" type="stmt"/> 165 - <line num="379" count="66" type="stmt"/> 166 - <line num="382" count="34" type="cond" truecount="1" falsecount="1"/> 167 - <line num="383" count="34" type="stmt"/> 168 - <line num="384" count="34" type="stmt"/> 169 - <line num="386" count="0" type="stmt"/> 170 - <line num="387" count="0" type="cond" truecount="0" falsecount="4"/> 171 - <line num="388" count="0" type="stmt"/> 172 - <line num="389" count="0" type="stmt"/> 173 - <line num="393" count="34" type="stmt"/> 174 - <line num="397" count="126" type="stmt"/> 175 - <line num="399" count="126" type="cond" truecount="5" falsecount="0"/> 176 - <line num="400" count="44" type="stmt"/> 177 - <line num="401" count="44" type="stmt"/> 178 - <line num="406" count="30" type="cond" truecount="6" falsecount="0"/> 179 - <line num="407" count="29" type="stmt"/> 180 - <line num="408" count="29" type="stmt"/> 181 - <line num="409" count="29" type="stmt"/> 182 - <line num="414" count="89" type="cond" truecount="2" falsecount="0"/> 183 - <line num="416" count="15" type="cond" truecount="1" falsecount="1"/> 184 - <line num="417" count="15" type="cond" truecount="2" falsecount="0"/> 185 - <line num="419" count="15" type="cond" truecount="2" falsecount="0"/> 186 - <line num="420" count="5" type="stmt"/> 187 - <line num="422" count="5" type="stmt"/> 188 - <line num="423" count="5" type="cond" truecount="1" falsecount="1"/> 189 - <line num="425" count="5" type="cond" truecount="1" falsecount="1"/> 190 - <line num="426" count="0" type="stmt"/> 191 - <line num="428" count="0" type="cond" truecount="0" falsecount="2"/> 192 - <line num="429" count="0" type="stmt"/> 193 - <line num="430" count="5" type="stmt"/> 194 - <line num="435" count="15" type="stmt"/> 195 - <line num="439" count="28" type="cond" truecount="4" falsecount="0"/> 196 - <line num="440" count="27" type="stmt"/> 197 - <line num="441" count="27" type="stmt"/> 198 - <line num="446" count="125" type="cond" truecount="3" falsecount="1"/> 199 - <line num="447" count="125" type="stmt"/> 200 - <line num="448" count="125" type="stmt"/> 201 - <line num="454" count="12" type="stmt"/> 202 - <line num="458" count="355" type="stmt"/> 203 - <line num="459" count="355" type="cond" truecount="3" falsecount="0"/> 204 - <line num="463" count="95" type="cond" truecount="2" falsecount="0"/> 205 - <line num="469" count="900" type="stmt"/> 206 - <line num="475" count="8" type="cond" truecount="2" falsecount="0"/> 207 - <line num="481" count="134" type="stmt"/> 208 - <line num="487" count="61" type="stmt"/> 209 - <line num="493" count="72" type="stmt"/> 210 - <line num="499" count="275" type="stmt"/> 211 - <line num="502" count="3" type="stmt"/> 212 - <line num="507" count="189" type="stmt"/> 213 - </file> 214 - </project> 215 - </coverage>
-2
coverage/coverage-final.json
··· 1 - {"/Users/joeldrapper/src/morphlex/src/morphlex.ts": {"path":"/Users/joeldrapper/src/morphlex/src/morphlex.ts","statementMap":{"0":{"start":{"line":53,"column":1},"end":{"line":53,"column":null}},"1":{"start":{"line":53,"column":36},"end":{"line":53,"column":null}},"2":{"start":{"line":54,"column":1},"end":{"line":54,"column":null}},"3":{"start":{"line":58,"column":1},"end":{"line":58,"column":null}},"4":{"start":{"line":58,"column":36},"end":{"line":58,"column":null}},"5":{"start":{"line":59,"column":1},"end":{"line":59,"column":null}},"6":{"start":{"line":63,"column":14},"end":{"line":63,"column":null}},"7":{"start":{"line":65,"column":1},"end":{"line":66,"column":null}},"8":{"start":{"line":65,"column":22},"end":{"line":65,"column":null}},"9":{"start":{"line":66,"column":6},"end":{"line":66,"column":null}},"10":{"start":{"line":70,"column":16},"end":{"line":70,"column":null}},"11":{"start":{"line":71,"column":13},"end":{"line":71,"column":null}},"12":{"start":{"line":73,"column":1},"end":{"line":74,"column":null}},"13":{"start":{"line":73,"column":34},"end":{"line":73,"column":null}},"14":{"start":{"line":74,"column":6},"end":{"line":74,"column":null}},"15":{"start":{"line":95,"column":2},"end":{"line":95,"column":null}},"16":{"start":{"line":96,"column":2},"end":{"line":96,"column":null}},"17":{"start":{"line":98,"column":2},"end":{"line":98,"column":null}},"18":{"start":{"line":99,"column":2},"end":{"line":99,"column":null}},"19":{"start":{"line":100,"column":2},"end":{"line":100,"column":null}},"20":{"start":{"line":101,"column":2},"end":{"line":101,"column":null}},"21":{"start":{"line":102,"column":2},"end":{"line":102,"column":null}},"22":{"start":{"line":103,"column":2},"end":{"line":103,"column":null}},"23":{"start":{"line":104,"column":2},"end":{"line":104,"column":null}},"24":{"start":{"line":105,"column":2},"end":{"line":105,"column":null}},"25":{"start":{"line":106,"column":2},"end":{"line":106,"column":null}},"26":{"start":{"line":107,"column":2},"end":{"line":107,"column":null}},"27":{"start":{"line":108,"column":2},"end":{"line":108,"column":null}},"28":{"start":{"line":109,"column":2},"end":{"line":109,"column":null}},"29":{"start":{"line":113,"column":2},"end":{"line":116,"column":null}},"30":{"start":{"line":114,"column":3},"end":{"line":114,"column":null}},"31":{"start":{"line":114,"column":31},"end":{"line":114,"column":null}},"32":{"start":{"line":115,"column":3},"end":{"line":115,"column":null}},"33":{"start":{"line":120,"column":2},"end":{"line":127,"column":null}},"34":{"start":{"line":121,"column":3},"end":{"line":126,"column":null}},"35":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"36":{"start":{"line":123,"column":4},"end":{"line":123,"column":null}},"37":{"start":{"line":125,"column":4},"end":{"line":125,"column":null}},"38":{"start":{"line":131,"column":2},"end":{"line":136,"column":null}},"39":{"start":{"line":132,"column":28},"end":{"line":132,"column":null}},"40":{"start":{"line":133,"column":3},"end":{"line":133,"column":null}},"41":{"start":{"line":134,"column":3},"end":{"line":134,"column":null}},"42":{"start":{"line":135,"column":3},"end":{"line":135,"column":null}},"43":{"start":{"line":136,"column":9},"end":{"line":136,"column":null}},"44":{"start":{"line":140,"column":2},"end":{"line":140,"column":null}},"45":{"start":{"line":141,"column":2},"end":{"line":141,"column":null}},"46":{"start":{"line":142,"column":2},"end":{"line":142,"column":null}},"47":{"start":{"line":146,"column":28},"end":{"line":146,"column":null}},"48":{"start":{"line":148,"column":34},"end":{"line":148,"column":null}},"49":{"start":{"line":149,"column":2},"end":{"line":173,"column":null}},"50":{"start":{"line":149,"column":15},"end":{"line":149,"column":18}},"51":{"start":{"line":150,"column":28},"end":{"line":150,"column":null}},"52":{"start":{"line":151,"column":19},"end":{"line":151,"column":null}},"53":{"start":{"line":153,"column":3},"end":{"line":165,"column":null}},"54":{"start":{"line":154,"column":4},"end":{"line":154,"column":null}},"55":{"start":{"line":156,"column":4},"end":{"line":156,"column":null}},"56":{"start":{"line":156,"column":66},"end":{"line":156,"column":null}},"57":{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},"58":{"start":{"line":157,"column":53},"end":{"line":157,"column":null}},"59":{"start":{"line":159,"column":4},"end":{"line":159,"column":null}},"60":{"start":{"line":161,"column":4},"end":{"line":164,"column":null}},"61":{"start":{"line":162,"column":5},"end":{"line":162,"column":null}},"62":{"start":{"line":162,"column":35},"end":{"line":162,"column":null}},"63":{"start":{"line":163,"column":5},"end":{"line":163,"column":null}},"64":{"start":{"line":163,"column":43},"end":{"line":163,"column":null}},"65":{"start":{"line":167,"column":47},"end":{"line":167,"column":null}},"66":{"start":{"line":168,"column":3},"end":{"line":172,"column":null}},"67":{"start":{"line":169,"column":4},"end":{"line":169,"column":null}},"68":{"start":{"line":170,"column":4},"end":{"line":170,"column":null}},"69":{"start":{"line":170,"column":26},"end":{"line":170,"column":null}},"70":{"start":{"line":171,"column":4},"end":{"line":171,"column":null}},"71":{"start":{"line":178,"column":26},"end":{"line":178,"column":null}},"72":{"start":{"line":180,"column":32},"end":{"line":180,"column":null}},"73":{"start":{"line":181,"column":2},"end":{"line":196,"column":null}},"74":{"start":{"line":181,"column":15},"end":{"line":181,"column":18}},"75":{"start":{"line":182,"column":25},"end":{"line":182,"column":null}},"76":{"start":{"line":183,"column":14},"end":{"line":183,"column":null}},"77":{"start":{"line":186,"column":3},"end":{"line":186,"column":null}},"78":{"start":{"line":186,"column":18},"end":{"line":186,"column":null}},"79":{"start":{"line":188,"column":47},"end":{"line":188,"column":null}},"80":{"start":{"line":190,"column":3},"end":{"line":195,"column":null}},"81":{"start":{"line":191,"column":37},"end":{"line":191,"column":null}},"82":{"start":{"line":192,"column":4},"end":{"line":192,"column":null}},"83":{"start":{"line":193,"column":4},"end":{"line":193,"column":null}},"84":{"start":{"line":193,"column":26},"end":{"line":193,"column":null}},"85":{"start":{"line":194,"column":4},"end":{"line":194,"column":null}},"86":{"start":{"line":201,"column":2},"end":{"line":202,"column":null}},"87":{"start":{"line":201,"column":35},"end":{"line":201,"column":null}},"88":{"start":{"line":202,"column":7},"end":{"line":202,"column":null}},"89":{"start":{"line":206,"column":28},"end":{"line":206,"column":null}},"90":{"start":{"line":208,"column":2},"end":{"line":208,"column":null}},"91":{"start":{"line":208,"column":75},"end":{"line":208,"column":null}},"92":{"start":{"line":210,"column":2},"end":{"line":210,"column":null}},"93":{"start":{"line":210,"column":57},"end":{"line":210,"column":null}},"94":{"start":{"line":213,"column":2},"end":{"line":213,"column":null}},"95":{"start":{"line":215,"column":2},"end":{"line":215,"column":null}},"96":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"97":{"start":{"line":219,"column":75},"end":{"line":219,"column":null}},"98":{"start":{"line":221,"column":2},"end":{"line":224,"column":null}},"99":{"start":{"line":223,"column":3},"end":{"line":223,"column":null}},"100":{"start":{"line":224,"column":9},"end":{"line":224,"column":null}},"101":{"start":{"line":226,"column":2},"end":{"line":226,"column":null}},"102":{"start":{"line":230,"column":28},"end":{"line":230,"column":null}},"103":{"start":{"line":232,"column":2},"end":{"line":235,"column":null}},"104":{"start":{"line":234,"column":3},"end":{"line":234,"column":null}},"105":{"start":{"line":235,"column":2},"end":{"line":235,"column":null}},"106":{"start":{"line":235,"column":64},"end":{"line":235,"column":null}},"107":{"start":{"line":239,"column":63},"end":{"line":239,"column":null}},"108":{"start":{"line":242,"column":34},"end":{"line":242,"column":null}},"109":{"start":{"line":243,"column":2},"end":{"line":246,"column":null}},"110":{"start":{"line":243,"column":15},"end":{"line":243,"column":18}},"111":{"start":{"line":244,"column":17},"end":{"line":244,"column":null}},"112":{"start":{"line":245,"column":3},"end":{"line":245,"column":null}},"113":{"start":{"line":249,"column":2},"end":{"line":257,"column":null}},"114":{"start":{"line":249,"column":15},"end":{"line":249,"column":41}},"115":{"start":{"line":250,"column":17},"end":{"line":250,"column":null}},"116":{"start":{"line":251,"column":15},"end":{"line":251,"column":null}},"117":{"start":{"line":252,"column":20},"end":{"line":252,"column":null}},"118":{"start":{"line":256,"column":3},"end":{"line":256,"column":null}},"119":{"start":{"line":260,"column":2},"end":{"line":260,"column":null}},"120":{"start":{"line":260,"column":52},"end":{"line":260,"column":null}},"121":{"start":{"line":265,"column":2},"end":{"line":270,"column":null}},"122":{"start":{"line":266,"column":3},"end":{"line":269,"column":null}},"123":{"start":{"line":267,"column":4},"end":{"line":267,"column":null}},"124":{"start":{"line":268,"column":4},"end":{"line":268,"column":null}},"125":{"start":{"line":273,"column":2},"end":{"line":279,"column":null}},"126":{"start":{"line":274,"column":25},"end":{"line":274,"column":null}},"127":{"start":{"line":275,"column":3},"end":{"line":278,"column":null}},"128":{"start":{"line":276,"column":4},"end":{"line":276,"column":null}},"129":{"start":{"line":277,"column":4},"end":{"line":277,"column":null}},"130":{"start":{"line":283,"column":2},"end":{"line":306,"column":null}},"131":{"start":{"line":284,"column":3},"end":{"line":284,"column":null}},"132":{"start":{"line":285,"column":3},"end":{"line":285,"column":null}},"133":{"start":{"line":286,"column":3},"end":{"line":286,"column":null}},"134":{"start":{"line":287,"column":3},"end":{"line":293,"column":null}},"135":{"start":{"line":292,"column":4},"end":{"line":292,"column":null}},"136":{"start":{"line":294,"column":2},"end":{"line":306,"column":null}},"137":{"start":{"line":295,"column":3},"end":{"line":295,"column":null}},"138":{"start":{"line":296,"column":2},"end":{"line":306,"column":null}},"139":{"start":{"line":302,"column":3},"end":{"line":302,"column":null}},"140":{"start":{"line":304,"column":16},"end":{"line":304,"column":null}},"141":{"start":{"line":305,"column":3},"end":{"line":305,"column":null}},"142":{"start":{"line":305,"column":13},"end":{"line":305,"column":null}},"143":{"start":{"line":311,"column":31},"end":{"line":311,"column":null}},"144":{"start":{"line":313,"column":21},"end":{"line":313,"column":null}},"145":{"start":{"line":314,"column":24},"end":{"line":314,"column":null}},"146":{"start":{"line":316,"column":2},"end":{"line":335,"column":null}},"147":{"start":{"line":316,"column":15},"end":{"line":316,"column":18}},"148":{"start":{"line":317,"column":17},"end":{"line":317,"column":null}},"149":{"start":{"line":318,"column":20},"end":{"line":318,"column":null}},"150":{"start":{"line":320,"column":3},"end":{"line":334,"column":null}},"151":{"start":{"line":321,"column":47},"end":{"line":321,"column":null}},"152":{"start":{"line":323,"column":4},"end":{"line":329,"column":null}},"153":{"start":{"line":324,"column":5},"end":{"line":328,"column":null}},"154":{"start":{"line":325,"column":6},"end":{"line":325,"column":null}},"155":{"start":{"line":327,"column":6},"end":{"line":327,"column":null}},"156":{"start":{"line":329,"column":11},"end":{"line":329,"column":null}},"157":{"start":{"line":330,"column":3},"end":{"line":334,"column":null}},"158":{"start":{"line":331,"column":4},"end":{"line":331,"column":null}},"159":{"start":{"line":332,"column":3},"end":{"line":334,"column":null}},"160":{"start":{"line":333,"column":4},"end":{"line":333,"column":null}},"161":{"start":{"line":338,"column":2},"end":{"line":341,"column":null}},"162":{"start":{"line":339,"column":17},"end":{"line":339,"column":null}},"163":{"start":{"line":340,"column":3},"end":{"line":340,"column":null}},"164":{"start":{"line":340,"column":14},"end":{"line":340,"column":null}},"165":{"start":{"line":345,"column":2},"end":{"line":345,"column":null}},"166":{"start":{"line":345,"column":76},"end":{"line":345,"column":null}},"167":{"start":{"line":347,"column":19},"end":{"line":347,"column":null}},"168":{"start":{"line":350,"column":22},"end":{"line":350,"column":null}},"169":{"start":{"line":352,"column":38},"end":{"line":352,"column":null}},"170":{"start":{"line":353,"column":45},"end":{"line":353,"column":null}},"171":{"start":{"line":356,"column":2},"end":{"line":380,"column":null}},"172":{"start":{"line":357,"column":3},"end":{"line":377,"column":null}},"173":{"start":{"line":358,"column":15},"end":{"line":358,"column":null}},"174":{"start":{"line":360,"column":4},"end":{"line":362,"column":null}},"175":{"start":{"line":361,"column":5},"end":{"line":361,"column":null}},"176":{"start":{"line":364,"column":4},"end":{"line":376,"column":null}},"177":{"start":{"line":365,"column":5},"end":{"line":375,"column":null}},"178":{"start":{"line":366,"column":6},"end":{"line":366,"column":null}},"179":{"start":{"line":367,"column":6},"end":{"line":367,"column":null}},"180":{"start":{"line":369,"column":27},"end":{"line":369,"column":null}},"181":{"start":{"line":371,"column":6},"end":{"line":374,"column":null}},"182":{"start":{"line":371,"column":51},"end":{"line":371,"column":71}},"183":{"start":{"line":372,"column":7},"end":{"line":372,"column":null}},"184":{"start":{"line":373,"column":7},"end":{"line":373,"column":null}},"185":{"start":{"line":379,"column":3},"end":{"line":379,"column":null}},"186":{"start":{"line":382,"column":2},"end":{"line":391,"column":null}},"187":{"start":{"line":383,"column":3},"end":{"line":383,"column":null}},"188":{"start":{"line":384,"column":3},"end":{"line":384,"column":null}},"189":{"start":{"line":386,"column":19},"end":{"line":386,"column":null}},"190":{"start":{"line":387,"column":3},"end":{"line":390,"column":null}},"191":{"start":{"line":388,"column":4},"end":{"line":388,"column":null}},"192":{"start":{"line":389,"column":4},"end":{"line":389,"column":null}},"193":{"start":{"line":393,"column":2},"end":{"line":393,"column":null}},"194":{"start":{"line":397,"column":24},"end":{"line":397,"column":null}},"195":{"start":{"line":399,"column":2},"end":{"line":402,"column":null}},"196":{"start":{"line":400,"column":3},"end":{"line":400,"column":null}},"197":{"start":{"line":401,"column":3},"end":{"line":401,"column":null}},"198":{"start":{"line":406,"column":2},"end":{"line":410,"column":null}},"199":{"start":{"line":407,"column":3},"end":{"line":407,"column":null}},"200":{"start":{"line":408,"column":3},"end":{"line":408,"column":null}},"201":{"start":{"line":409,"column":3},"end":{"line":409,"column":null}},"202":{"start":{"line":414,"column":2},"end":{"line":414,"column":null}},"203":{"start":{"line":414,"column":31},"end":{"line":414,"column":null}},"204":{"start":{"line":416,"column":2},"end":{"line":433,"column":null}},"205":{"start":{"line":417,"column":23},"end":{"line":417,"column":null}},"206":{"start":{"line":419,"column":3},"end":{"line":432,"column":null}},"207":{"start":{"line":420,"column":23},"end":{"line":420,"column":null}},"208":{"start":{"line":422,"column":4},"end":{"line":431,"column":null}},"209":{"start":{"line":423,"column":37},"end":{"line":423,"column":null}},"210":{"start":{"line":425,"column":5},"end":{"line":430,"column":null}},"211":{"start":{"line":426,"column":6},"end":{"line":426,"column":null}},"212":{"start":{"line":428,"column":6},"end":{"line":428,"column":null}},"213":{"start":{"line":428,"column":43},"end":{"line":428,"column":null}},"214":{"start":{"line":429,"column":6},"end":{"line":429,"column":null}},"215":{"start":{"line":430,"column":12},"end":{"line":430,"column":null}},"216":{"start":{"line":435,"column":2},"end":{"line":435,"column":null}},"217":{"start":{"line":439,"column":2},"end":{"line":442,"column":null}},"218":{"start":{"line":440,"column":3},"end":{"line":440,"column":null}},"219":{"start":{"line":441,"column":3},"end":{"line":441,"column":null}},"220":{"start":{"line":446,"column":2},"end":{"line":449,"column":null}},"221":{"start":{"line":447,"column":3},"end":{"line":447,"column":null}},"222":{"start":{"line":448,"column":3},"end":{"line":448,"column":null}},"223":{"start":{"line":454,"column":1},"end":{"line":454,"column":null}},"224":{"start":{"line":458,"column":16},"end":{"line":458,"column":null}},"225":{"start":{"line":459,"column":1},"end":{"line":459,"column":null}},"226":{"start":{"line":463,"column":1},"end":{"line":463,"column":null}},"227":{"start":{"line":469,"column":1},"end":{"line":469,"column":null}},"228":{"start":{"line":475,"column":1},"end":{"line":475,"column":null}},"229":{"start":{"line":481,"column":1},"end":{"line":481,"column":null}},"230":{"start":{"line":487,"column":1},"end":{"line":487,"column":null}},"231":{"start":{"line":493,"column":1},"end":{"line":493,"column":null}},"232":{"start":{"line":499,"column":1},"end":{"line":499,"column":null}},"233":{"start":{"line":502,"column":24},"end":{"line":502,"column":null}},"234":{"start":{"line":507,"column":1},"end":{"line":507,"column":null}}},"fnMap":{"0":{"name":"morph","decl":{"start":{"line":52,"column":16},"end":{"line":52,"column":22}},"loc":{"start":{"line":52,"column":99},"end":{"line":55,"column":null}},"line":52},"1":{"name":"morphInner","decl":{"start":{"line":57,"column":16},"end":{"line":57,"column":27}},"loc":{"start":{"line":57,"column":103},"end":{"line":60,"column":null}},"line":57},"2":{"name":"parseElementFromString","decl":{"start":{"line":62,"column":9},"end":{"line":62,"column":32}},"loc":{"start":{"line":62,"column":57},"end":{"line":67,"column":null}},"line":62},"3":{"name":"parseChildNodeFromString","decl":{"start":{"line":69,"column":9},"end":{"line":69,"column":34}},"loc":{"start":{"line":69,"column":61},"end":{"line":75,"column":null}},"line":69},"4":{"name":"(anonymous_4)","decl":{"start":{"line":94,"column":1},"end":{"line":94,"column":13}},"loc":{"start":{"line":94,"column":36},"end":{"line":110,"column":null}},"line":94},"5":{"name":"(anonymous_5)","decl":{"start":{"line":112,"column":1},"end":{"line":112,"column":7}},"loc":{"start":{"line":112,"column":49},"end":{"line":117,"column":null}},"line":112},"6":{"name":"(anonymous_6)","decl":{"start":{"line":113,"column":30},"end":{"line":113,"column":36}},"loc":{"start":{"line":113,"column":36},"end":{"line":116,"column":3}},"line":113},"7":{"name":"(anonymous_7)","decl":{"start":{"line":119,"column":1},"end":{"line":119,"column":12}},"loc":{"start":{"line":119,"column":52},"end":{"line":128,"column":null}},"line":119},"8":{"name":"(anonymous_8)","decl":{"start":{"line":120,"column":30},"end":{"line":120,"column":36}},"loc":{"start":{"line":120,"column":36},"end":{"line":127,"column":3}},"line":120},"9":{"name":"(anonymous_9)","decl":{"start":{"line":130,"column":1},"end":{"line":130,"column":15}},"loc":{"start":{"line":130,"column":52},"end":{"line":137,"column":null}},"line":130},"10":{"name":"(anonymous_10)","decl":{"start":{"line":139,"column":1},"end":{"line":139,"column":12}},"loc":{"start":{"line":139,"column":68},"end":{"line":143,"column":null}},"line":139},"11":{"name":"(anonymous_11)","decl":{"start":{"line":145,"column":1},"end":{"line":145,"column":15}},"loc":{"start":{"line":145,"column":53},"end":{"line":174,"column":null}},"line":145},"12":{"name":"(anonymous_12)","decl":{"start":{"line":177,"column":1},"end":{"line":177,"column":12}},"loc":{"start":{"line":177,"column":50},"end":{"line":197,"column":null}},"line":177},"13":{"name":"(anonymous_13)","decl":{"start":{"line":200,"column":1},"end":{"line":200,"column":12}},"loc":{"start":{"line":200,"column":54},"end":{"line":203,"column":null}},"line":200},"14":{"name":"(anonymous_14)","decl":{"start":{"line":205,"column":1},"end":{"line":205,"column":27}},"loc":{"start":{"line":205,"column":78},"end":{"line":216,"column":null}},"line":205},"15":{"name":"(anonymous_15)","decl":{"start":{"line":218,"column":1},"end":{"line":218,"column":17}},"loc":{"start":{"line":218,"column":72},"end":{"line":227,"column":null}},"line":218},"16":{"name":"(anonymous_16)","decl":{"start":{"line":229,"column":1},"end":{"line":229,"column":30}},"loc":{"start":{"line":229,"column":81},"end":{"line":236,"column":null}},"line":229},"17":{"name":"(anonymous_17)","decl":{"start":{"line":238,"column":1},"end":{"line":238,"column":20}},"loc":{"start":{"line":238,"column":92},"end":{"line":261,"column":null}},"line":238},"18":{"name":"(anonymous_18)","decl":{"start":{"line":263,"column":1},"end":{"line":263,"column":18}},"loc":{"start":{"line":263,"column":85},"end":{"line":307,"column":null}},"line":263},"19":{"name":"(anonymous_19)","decl":{"start":{"line":310,"column":1},"end":{"line":310,"column":18}},"loc":{"start":{"line":310,"column":69},"end":{"line":342,"column":null}},"line":310},"20":{"name":"(anonymous_20)","decl":{"start":{"line":344,"column":1},"end":{"line":344,"column":20}},"loc":{"start":{"line":344,"column":102},"end":{"line":394,"column":null}},"line":344},"21":{"name":"(anonymous_21)","decl":{"start":{"line":371,"column":43},"end":{"line":371,"column":44}},"loc":{"start":{"line":371,"column":51},"end":{"line":371,"column":71}},"line":371},"22":{"name":"(anonymous_22)","decl":{"start":{"line":396,"column":1},"end":{"line":396,"column":52}},"loc":{"start":{"line":396,"column":100},"end":{"line":403,"column":null}},"line":396},"23":{"name":"(anonymous_23)","decl":{"start":{"line":405,"column":1},"end":{"line":405,"column":14}},"loc":{"start":{"line":405,"column":52},"end":{"line":411,"column":null}},"line":405},"24":{"name":"(anonymous_24)","decl":{"start":{"line":413,"column":1},"end":{"line":413,"column":15}},"loc":{"start":{"line":413,"column":80},"end":{"line":436,"column":null}},"line":413},"25":{"name":"(anonymous_25)","decl":{"start":{"line":438,"column":1},"end":{"line":438,"column":14}},"loc":{"start":{"line":438,"column":53},"end":{"line":443,"column":null}},"line":438},"26":{"name":"(anonymous_26)","decl":{"start":{"line":445,"column":1},"end":{"line":445,"column":13}},"loc":{"start":{"line":445,"column":36},"end":{"line":450,"column":null}},"line":445},"27":{"name":"writableNode","decl":{"start":{"line":453,"column":9},"end":{"line":453,"column":38}},"loc":{"start":{"line":453,"column":64},"end":{"line":455,"column":null}},"line":453},"28":{"name":"isMatchingElementPair","decl":{"start":{"line":457,"column":9},"end":{"line":457,"column":31}},"loc":{"start":{"line":457,"column":109},"end":{"line":460,"column":null}},"line":457},"29":{"name":"isParentNodePair","decl":{"start":{"line":462,"column":9},"end":{"line":462,"column":26}},"loc":{"start":{"line":462,"column":96},"end":{"line":464,"column":null}},"line":462},"30":{"name":"isElement","decl":{"start":{"line":468,"column":9},"end":{"line":468,"column":19}},"loc":{"start":{"line":468,"column":61},"end":{"line":470,"column":null}},"line":468},"31":{"name":"isMedia","decl":{"start":{"line":474,"column":9},"end":{"line":474,"column":17}},"loc":{"start":{"line":474,"column":68},"end":{"line":476,"column":null}},"line":474},"32":{"name":"isInput","decl":{"start":{"line":480,"column":9},"end":{"line":480,"column":17}},"loc":{"start":{"line":480,"column":68},"end":{"line":482,"column":null}},"line":480},"33":{"name":"isOption","decl":{"start":{"line":486,"column":9},"end":{"line":486,"column":18}},"loc":{"start":{"line":486,"column":69},"end":{"line":488,"column":null}},"line":486},"34":{"name":"isTextArea","decl":{"start":{"line":492,"column":9},"end":{"line":492,"column":20}},"loc":{"start":{"line":492,"column":71},"end":{"line":494,"column":null}},"line":492},"35":{"name":"isHead","decl":{"start":{"line":498,"column":9},"end":{"line":498,"column":16}},"loc":{"start":{"line":498,"column":67},"end":{"line":500,"column":null}},"line":498},"36":{"name":"isParentNode","decl":{"start":{"line":506,"column":9},"end":{"line":506,"column":22}},"loc":{"start":{"line":506,"column":64},"end":{"line":508,"column":null}},"line":506}},"branchMap":{"0":{"loc":{"start":{"line":52,"column":70},"end":{"line":52,"column":99}},"type":"default-arg","locations":[{"start":{"line":52,"column":89},"end":{"line":52,"column":99}}],"line":52},"1":{"loc":{"start":{"line":53,"column":1},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":1},"end":{"line":53,"column":null}},{"start":{},"end":{}}],"line":53},"2":{"loc":{"start":{"line":57,"column":74},"end":{"line":57,"column":103}},"type":"default-arg","locations":[{"start":{"line":57,"column":93},"end":{"line":57,"column":103}}],"line":57},"3":{"loc":{"start":{"line":58,"column":1},"end":{"line":58,"column":null}},"type":"if","locations":[{"start":{"line":58,"column":1},"end":{"line":58,"column":null}},{"start":{},"end":{}}],"line":58},"4":{"loc":{"start":{"line":65,"column":1},"end":{"line":66,"column":null}},"type":"if","locations":[{"start":{"line":65,"column":1},"end":{"line":66,"column":null}},{"start":{"line":66,"column":6},"end":{"line":66,"column":null}}],"line":65},"5":{"loc":{"start":{"line":73,"column":1},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":73,"column":1},"end":{"line":74,"column":null}},{"start":{"line":74,"column":6},"end":{"line":74,"column":null}}],"line":73},"6":{"loc":{"start":{"line":94,"column":13},"end":{"line":94,"column":36}},"type":"default-arg","locations":[{"start":{"line":94,"column":32},"end":{"line":94,"column":36}}],"line":94},"7":{"loc":{"start":{"line":98,"column":28},"end":{"line":98,"column":null}},"type":"binary-expr","locations":[{"start":{"line":98,"column":28},"end":{"line":98,"column":57}},{"start":{"line":98,"column":57},"end":{"line":98,"column":null}}],"line":98},"8":{"loc":{"start":{"line":99,"column":33},"end":{"line":99,"column":null}},"type":"binary-expr","locations":[{"start":{"line":99,"column":33},"end":{"line":99,"column":67}},{"start":{"line":99,"column":67},"end":{"line":99,"column":null}}],"line":99},"9":{"loc":{"start":{"line":114,"column":3},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":114,"column":3},"end":{"line":114,"column":null}},{"start":{},"end":{}}],"line":114},"10":{"loc":{"start":{"line":121,"column":3},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":121,"column":3},"end":{"line":126,"column":null}},{"start":{"line":124,"column":10},"end":{"line":126,"column":null}}],"line":121},"11":{"loc":{"start":{"line":131,"column":2},"end":{"line":136,"column":null}},"type":"if","locations":[{"start":{"line":131,"column":2},"end":{"line":136,"column":null}},{"start":{"line":136,"column":9},"end":{"line":136,"column":null}}],"line":131},"12":{"loc":{"start":{"line":153,"column":3},"end":{"line":165,"column":null}},"type":"if","locations":[{"start":{"line":153,"column":3},"end":{"line":165,"column":null}},{"start":{"line":158,"column":10},"end":{"line":165,"column":null}}],"line":153},"13":{"loc":{"start":{"line":153,"column":7},"end":{"line":153,"column":66}},"type":"binary-expr","locations":[{"start":{"line":153,"column":7},"end":{"line":153,"column":36}},{"start":{"line":153,"column":36},"end":{"line":153,"column":66}}],"line":153},"14":{"loc":{"start":{"line":156,"column":4},"end":{"line":156,"column":null}},"type":"if","locations":[{"start":{"line":156,"column":4},"end":{"line":156,"column":null}},{"start":{},"end":{}}],"line":156},"15":{"loc":{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},"type":"if","locations":[{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},{"start":{},"end":{}}],"line":157},"16":{"loc":{"start":{"line":161,"column":4},"end":{"line":164,"column":null}},"type":"if","locations":[{"start":{"line":161,"column":4},"end":{"line":164,"column":null}},{"start":{},"end":{}}],"line":161},"17":{"loc":{"start":{"line":161,"column":8},"end":{"line":161,"column":62}},"type":"binary-expr","locations":[{"start":{"line":161,"column":8},"end":{"line":161,"column":37}},{"start":{"line":161,"column":37},"end":{"line":161,"column":62}}],"line":161},"18":{"loc":{"start":{"line":162,"column":5},"end":{"line":162,"column":null}},"type":"if","locations":[{"start":{"line":162,"column":5},"end":{"line":162,"column":null}},{"start":{},"end":{}}],"line":162},"19":{"loc":{"start":{"line":163,"column":5},"end":{"line":163,"column":null}},"type":"if","locations":[{"start":{"line":163,"column":5},"end":{"line":163,"column":null}},{"start":{},"end":{}}],"line":163},"20":{"loc":{"start":{"line":169,"column":37},"end":{"line":169,"column":77}},"type":"binary-expr","locations":[{"start":{"line":169,"column":37},"end":{"line":169,"column":72}},{"start":{"line":169,"column":72},"end":{"line":169,"column":77}}],"line":169},"21":{"loc":{"start":{"line":170,"column":4},"end":{"line":170,"column":null}},"type":"if","locations":[{"start":{"line":170,"column":4},"end":{"line":170,"column":null}},{"start":{},"end":{}}],"line":170},"22":{"loc":{"start":{"line":186,"column":3},"end":{"line":186,"column":null}},"type":"if","locations":[{"start":{"line":186,"column":3},"end":{"line":186,"column":null}},{"start":{},"end":{}}],"line":186},"23":{"loc":{"start":{"line":192,"column":4},"end":{"line":192,"column":null}},"type":"cond-expr","locations":[{"start":{"line":192,"column":12},"end":{"line":192,"column":28}},{"start":{"line":192,"column":28},"end":{"line":192,"column":null}}],"line":192},"24":{"loc":{"start":{"line":193,"column":4},"end":{"line":193,"column":null}},"type":"if","locations":[{"start":{"line":193,"column":4},"end":{"line":193,"column":null}},{"start":{},"end":{}}],"line":193},"25":{"loc":{"start":{"line":201,"column":2},"end":{"line":202,"column":null}},"type":"if","locations":[{"start":{"line":201,"column":2},"end":{"line":202,"column":null}},{"start":{"line":202,"column":7},"end":{"line":202,"column":null}}],"line":201},"26":{"loc":{"start":{"line":208,"column":2},"end":{"line":208,"column":null}},"type":"if","locations":[{"start":{"line":208,"column":2},"end":{"line":208,"column":null}},{"start":{},"end":{}}],"line":208},"27":{"loc":{"start":{"line":208,"column":8},"end":{"line":208,"column":75}},"type":"binary-expr","locations":[{"start":{"line":208,"column":8},"end":{"line":208,"column":68}},{"start":{"line":208,"column":68},"end":{"line":208,"column":75}}],"line":208},"28":{"loc":{"start":{"line":210,"column":2},"end":{"line":210,"column":null}},"type":"if","locations":[{"start":{"line":210,"column":2},"end":{"line":210,"column":null}},{"start":{},"end":{}}],"line":210},"29":{"loc":{"start":{"line":210,"column":6},"end":{"line":210,"column":57}},"type":"binary-expr","locations":[{"start":{"line":210,"column":6},"end":{"line":210,"column":30}},{"start":{"line":210,"column":30},"end":{"line":210,"column":57}}],"line":210},"30":{"loc":{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},"type":"if","locations":[{"start":{"line":219,"column":2},"end":{"line":219,"column":null}},{"start":{},"end":{}}],"line":219},"31":{"loc":{"start":{"line":219,"column":8},"end":{"line":219,"column":75}},"type":"binary-expr","locations":[{"start":{"line":219,"column":8},"end":{"line":219,"column":68}},{"start":{"line":219,"column":68},"end":{"line":219,"column":75}}],"line":219},"32":{"loc":{"start":{"line":221,"column":2},"end":{"line":224,"column":null}},"type":"if","locations":[{"start":{"line":221,"column":2},"end":{"line":224,"column":null}},{"start":{"line":224,"column":9},"end":{"line":224,"column":null}}],"line":221},"33":{"loc":{"start":{"line":221,"column":6},"end":{"line":221,"column":103}},"type":"binary-expr","locations":[{"start":{"line":221,"column":6},"end":{"line":221,"column":46}},{"start":{"line":221,"column":46},"end":{"line":221,"column":73}},{"start":{"line":221,"column":73},"end":{"line":221,"column":103}}],"line":221},"34":{"loc":{"start":{"line":232,"column":2},"end":{"line":235,"column":null}},"type":"if","locations":[{"start":{"line":232,"column":2},"end":{"line":235,"column":null}},{"start":{"line":235,"column":2},"end":{"line":235,"column":null}}],"line":232},"35":{"loc":{"start":{"line":235,"column":2},"end":{"line":235,"column":null}},"type":"if","locations":[{"start":{"line":235,"column":2},"end":{"line":235,"column":null}},{"start":{},"end":{}}],"line":235},"36":{"loc":{"start":{"line":235,"column":13},"end":{"line":235,"column":64}},"type":"binary-expr","locations":[{"start":{"line":235,"column":13},"end":{"line":235,"column":37}},{"start":{"line":235,"column":37},"end":{"line":235,"column":64}}],"line":235},"37":{"loc":{"start":{"line":256,"column":3},"end":{"line":256,"column":null}},"type":"cond-expr","locations":[{"start":{"line":256,"column":14},"end":{"line":256,"column":45}},{"start":{"line":256,"column":45},"end":{"line":256,"column":null}}],"line":256},"38":{"loc":{"start":{"line":266,"column":3},"end":{"line":269,"column":null}},"type":"if","locations":[{"start":{"line":266,"column":3},"end":{"line":269,"column":null}},{"start":{},"end":{}}],"line":266},"39":{"loc":{"start":{"line":266,"column":7},"end":{"line":266,"column":103}},"type":"binary-expr","locations":[{"start":{"line":266,"column":7},"end":{"line":266,"column":41}},{"start":{"line":266,"column":41},"end":{"line":266,"column":96}},{"start":{"line":266,"column":96},"end":{"line":266,"column":103}}],"line":266},"40":{"loc":{"start":{"line":275,"column":3},"end":{"line":278,"column":null}},"type":"if","locations":[{"start":{"line":275,"column":3},"end":{"line":278,"column":null}},{"start":{},"end":{}}],"line":275},"41":{"loc":{"start":{"line":275,"column":7},"end":{"line":275,"column":98}},"type":"binary-expr","locations":[{"start":{"line":275,"column":7},"end":{"line":275,"column":35}},{"start":{"line":275,"column":35},"end":{"line":275,"column":91}},{"start":{"line":275,"column":91},"end":{"line":275,"column":98}}],"line":275},"42":{"loc":{"start":{"line":283,"column":2},"end":{"line":306,"column":null}},"type":"if","locations":[{"start":{"line":283,"column":2},"end":{"line":306,"column":null}},{"start":{"line":294,"column":2},"end":{"line":306,"column":null}}],"line":283},"43":{"loc":{"start":{"line":283,"column":6},"end":{"line":283,"column":46}},"type":"binary-expr","locations":[{"start":{"line":283,"column":6},"end":{"line":283,"column":26}},{"start":{"line":283,"column":26},"end":{"line":283,"column":46}}],"line":283},"44":{"loc":{"start":{"line":287,"column":3},"end":{"line":293,"column":null}},"type":"if","locations":[{"start":{"line":287,"column":3},"end":{"line":293,"column":null}},{"start":{},"end":{}}],"line":287},"45":{"loc":{"start":{"line":288,"column":4},"end":{"line":290,"column":null}},"type":"binary-expr","locations":[{"start":{"line":288,"column":4},"end":{"line":288,"column":null}},{"start":{"line":289,"column":4},"end":{"line":289,"column":null}},{"start":{"line":290,"column":4},"end":{"line":290,"column":null}}],"line":288},"46":{"loc":{"start":{"line":290,"column":6},"end":{"line":290,"column":null}},"type":"binary-expr","locations":[{"start":{"line":290,"column":6},"end":{"line":290,"column":38}},{"start":{"line":290,"column":38},"end":{"line":290,"column":73}},{"start":{"line":290,"column":73},"end":{"line":290,"column":null}}],"line":290},"47":{"loc":{"start":{"line":294,"column":2},"end":{"line":306,"column":null}},"type":"if","locations":[{"start":{"line":294,"column":2},"end":{"line":306,"column":null}},{"start":{"line":296,"column":2},"end":{"line":306,"column":null}}],"line":294},"48":{"loc":{"start":{"line":294,"column":13},"end":{"line":294,"column":55}},"type":"binary-expr","locations":[{"start":{"line":294,"column":13},"end":{"line":294,"column":34}},{"start":{"line":294,"column":34},"end":{"line":294,"column":55}}],"line":294},"49":{"loc":{"start":{"line":296,"column":2},"end":{"line":306,"column":null}},"type":"if","locations":[{"start":{"line":296,"column":2},"end":{"line":306,"column":null}},{"start":{},"end":{}}],"line":296},"50":{"loc":{"start":{"line":297,"column":3},"end":{"line":300,"column":null}},"type":"binary-expr","locations":[{"start":{"line":297,"column":3},"end":{"line":297,"column":null}},{"start":{"line":298,"column":3},"end":{"line":298,"column":null}},{"start":{"line":299,"column":3},"end":{"line":299,"column":null}},{"start":{"line":300,"column":3},"end":{"line":300,"column":null}}],"line":297},"51":{"loc":{"start":{"line":300,"column":5},"end":{"line":300,"column":null}},"type":"binary-expr","locations":[{"start":{"line":300,"column":5},"end":{"line":300,"column":37}},{"start":{"line":300,"column":37},"end":{"line":300,"column":72}},{"start":{"line":300,"column":72},"end":{"line":300,"column":null}}],"line":300},"52":{"loc":{"start":{"line":305,"column":3},"end":{"line":305,"column":null}},"type":"if","locations":[{"start":{"line":305,"column":3},"end":{"line":305,"column":null}},{"start":{},"end":{}}],"line":305},"53":{"loc":{"start":{"line":320,"column":3},"end":{"line":334,"column":null}},"type":"if","locations":[{"start":{"line":320,"column":3},"end":{"line":334,"column":null}},{"start":{"line":330,"column":3},"end":{"line":334,"column":null}}],"line":320},"54":{"loc":{"start":{"line":320,"column":7},"end":{"line":320,"column":26}},"type":"binary-expr","locations":[{"start":{"line":320,"column":7},"end":{"line":320,"column":16}},{"start":{"line":320,"column":16},"end":{"line":320,"column":26}}],"line":320},"55":{"loc":{"start":{"line":323,"column":4},"end":{"line":329,"column":null}},"type":"if","locations":[{"start":{"line":323,"column":4},"end":{"line":329,"column":null}},{"start":{"line":329,"column":11},"end":{"line":329,"column":null}}],"line":323},"56":{"loc":{"start":{"line":324,"column":5},"end":{"line":328,"column":null}},"type":"if","locations":[{"start":{"line":324,"column":5},"end":{"line":328,"column":null}},{"start":{"line":326,"column":12},"end":{"line":328,"column":null}}],"line":324},"57":{"loc":{"start":{"line":330,"column":3},"end":{"line":334,"column":null}},"type":"if","locations":[{"start":{"line":330,"column":3},"end":{"line":334,"column":null}},{"start":{"line":332,"column":3},"end":{"line":334,"column":null}}],"line":330},"58":{"loc":{"start":{"line":332,"column":3},"end":{"line":334,"column":null}},"type":"if","locations":[{"start":{"line":332,"column":3},"end":{"line":334,"column":null}},{"start":{},"end":{}}],"line":332},"59":{"loc":{"start":{"line":340,"column":3},"end":{"line":340,"column":null}},"type":"if","locations":[{"start":{"line":340,"column":3},"end":{"line":340,"column":null}},{"start":{},"end":{}}],"line":340},"60":{"loc":{"start":{"line":345,"column":2},"end":{"line":345,"column":null}},"type":"if","locations":[{"start":{"line":345,"column":2},"end":{"line":345,"column":null}},{"start":{},"end":{}}],"line":345},"61":{"loc":{"start":{"line":345,"column":8},"end":{"line":345,"column":76}},"type":"binary-expr","locations":[{"start":{"line":345,"column":8},"end":{"line":345,"column":69}},{"start":{"line":345,"column":69},"end":{"line":345,"column":76}}],"line":345},"62":{"loc":{"start":{"line":350,"column":22},"end":{"line":350,"column":null}},"type":"cond-expr","locations":[{"start":{"line":350,"column":33},"end":{"line":350,"column":49}},{"start":{"line":350,"column":49},"end":{"line":350,"column":null}}],"line":350},"63":{"loc":{"start":{"line":357,"column":3},"end":{"line":377,"column":null}},"type":"if","locations":[{"start":{"line":357,"column":3},"end":{"line":377,"column":null}},{"start":{},"end":{}}],"line":357},"64":{"loc":{"start":{"line":360,"column":4},"end":{"line":362,"column":null}},"type":"if","locations":[{"start":{"line":360,"column":4},"end":{"line":362,"column":null}},{"start":{},"end":{}}],"line":360},"65":{"loc":{"start":{"line":360,"column":8},"end":{"line":360,"column":78}},"type":"binary-expr","locations":[{"start":{"line":360,"column":8},"end":{"line":360,"column":31}},{"start":{"line":360,"column":31},"end":{"line":360,"column":78}}],"line":360},"66":{"loc":{"start":{"line":364,"column":4},"end":{"line":376,"column":null}},"type":"if","locations":[{"start":{"line":364,"column":4},"end":{"line":376,"column":null}},{"start":{},"end":{}}],"line":364},"67":{"loc":{"start":{"line":365,"column":5},"end":{"line":375,"column":null}},"type":"if","locations":[{"start":{"line":365,"column":5},"end":{"line":375,"column":null}},{"start":{"line":368,"column":12},"end":{"line":375,"column":null}}],"line":365},"68":{"loc":{"start":{"line":371,"column":6},"end":{"line":374,"column":null}},"type":"if","locations":[{"start":{"line":371,"column":6},"end":{"line":374,"column":null}},{"start":{},"end":{}}],"line":371},"69":{"loc":{"start":{"line":371,"column":10},"end":{"line":371,"column":74}},"type":"binary-expr","locations":[{"start":{"line":371,"column":10},"end":{"line":371,"column":26}},{"start":{"line":371,"column":26},"end":{"line":371,"column":74}}],"line":371},"70":{"loc":{"start":{"line":382,"column":2},"end":{"line":391,"column":null}},"type":"if","locations":[{"start":{"line":382,"column":2},"end":{"line":391,"column":null}},{"start":{"line":385,"column":9},"end":{"line":391,"column":null}}],"line":382},"71":{"loc":{"start":{"line":387,"column":3},"end":{"line":390,"column":null}},"type":"if","locations":[{"start":{"line":387,"column":3},"end":{"line":390,"column":null}},{"start":{},"end":{}}],"line":387},"72":{"loc":{"start":{"line":387,"column":7},"end":{"line":387,"column":49}},"type":"binary-expr","locations":[{"start":{"line":387,"column":7},"end":{"line":387,"column":43}},{"start":{"line":387,"column":43},"end":{"line":387,"column":49}}],"line":387},"73":{"loc":{"start":{"line":399,"column":2},"end":{"line":402,"column":null}},"type":"if","locations":[{"start":{"line":399,"column":2},"end":{"line":402,"column":null}},{"start":{},"end":{}}],"line":399},"74":{"loc":{"start":{"line":399,"column":6},"end":{"line":399,"column":107}},"type":"binary-expr","locations":[{"start":{"line":399,"column":6},"end":{"line":399,"column":37}},{"start":{"line":399,"column":37},"end":{"line":399,"column":100}},{"start":{"line":399,"column":100},"end":{"line":399,"column":107}}],"line":399},"75":{"loc":{"start":{"line":406,"column":2},"end":{"line":410,"column":null}},"type":"if","locations":[{"start":{"line":406,"column":2},"end":{"line":410,"column":null}},{"start":{},"end":{}}],"line":406},"76":{"loc":{"start":{"line":406,"column":2},"end":{"line":406,"column":95}},"type":"binary-expr","locations":[{"start":{"line":406,"column":7},"end":{"line":406,"column":42}},{"start":{"line":406,"column":42},"end":{"line":406,"column":52}},{"start":{"line":406,"column":52},"end":{"line":406,"column":88}},{"start":{"line":406,"column":88},"end":{"line":406,"column":95}}],"line":406},"77":{"loc":{"start":{"line":414,"column":2},"end":{"line":414,"column":null}},"type":"if","locations":[{"start":{"line":414,"column":2},"end":{"line":414,"column":null}},{"start":{},"end":{}}],"line":414},"78":{"loc":{"start":{"line":416,"column":2},"end":{"line":433,"column":null}},"type":"if","locations":[{"start":{"line":416,"column":2},"end":{"line":433,"column":null}},{"start":{},"end":{}}],"line":416},"79":{"loc":{"start":{"line":417,"column":23},"end":{"line":417,"column":null}},"type":"binary-expr","locations":[{"start":{"line":417,"column":23},"end":{"line":417,"column":55}},{"start":{"line":417,"column":55},"end":{"line":417,"column":null}}],"line":417},"80":{"loc":{"start":{"line":419,"column":3},"end":{"line":432,"column":null}},"type":"if","locations":[{"start":{"line":419,"column":3},"end":{"line":432,"column":null}},{"start":{},"end":{}}],"line":419},"81":{"loc":{"start":{"line":423,"column":37},"end":{"line":423,"column":null}},"type":"binary-expr","locations":[{"start":{"line":423,"column":37},"end":{"line":423,"column":77}},{"start":{"line":423,"column":77},"end":{"line":423,"column":null}}],"line":423},"82":{"loc":{"start":{"line":425,"column":5},"end":{"line":430,"column":null}},"type":"if","locations":[{"start":{"line":425,"column":5},"end":{"line":430,"column":null}},{"start":{"line":430,"column":12},"end":{"line":430,"column":null}}],"line":425},"83":{"loc":{"start":{"line":428,"column":6},"end":{"line":428,"column":null}},"type":"if","locations":[{"start":{"line":428,"column":6},"end":{"line":428,"column":null}},{"start":{},"end":{}}],"line":428},"84":{"loc":{"start":{"line":439,"column":2},"end":{"line":442,"column":null}},"type":"if","locations":[{"start":{"line":439,"column":2},"end":{"line":442,"column":null}},{"start":{},"end":{}}],"line":439},"85":{"loc":{"start":{"line":439,"column":6},"end":{"line":439,"column":48}},"type":"binary-expr","locations":[{"start":{"line":439,"column":6},"end":{"line":439,"column":42}},{"start":{"line":439,"column":42},"end":{"line":439,"column":48}}],"line":439},"86":{"loc":{"start":{"line":446,"column":2},"end":{"line":449,"column":null}},"type":"if","locations":[{"start":{"line":446,"column":2},"end":{"line":449,"column":null}},{"start":{},"end":{}}],"line":446},"87":{"loc":{"start":{"line":446,"column":6},"end":{"line":446,"column":47}},"type":"binary-expr","locations":[{"start":{"line":446,"column":6},"end":{"line":446,"column":41}},{"start":{"line":446,"column":41},"end":{"line":446,"column":47}}],"line":446},"88":{"loc":{"start":{"line":459,"column":8},"end":{"line":459,"column":null}},"type":"binary-expr","locations":[{"start":{"line":459,"column":8},"end":{"line":459,"column":24}},{"start":{"line":459,"column":24},"end":{"line":459,"column":40}},{"start":{"line":459,"column":40},"end":{"line":459,"column":null}}],"line":459},"89":{"loc":{"start":{"line":463,"column":8},"end":{"line":463,"column":null}},"type":"binary-expr","locations":[{"start":{"line":463,"column":8},"end":{"line":463,"column":33}},{"start":{"line":463,"column":33},"end":{"line":463,"column":null}}],"line":463},"90":{"loc":{"start":{"line":475,"column":8},"end":{"line":475,"column":null}},"type":"binary-expr","locations":[{"start":{"line":475,"column":8},"end":{"line":475,"column":41}},{"start":{"line":475,"column":41},"end":{"line":475,"column":null}}],"line":475}},"s":{"0":95,"1":4,"2":95,"3":7,"4":1,"5":6,"6":1,"7":1,"8":0,"9":1,"10":5,"11":5,"12":5,"13":5,"14":0,"15":101,"16":101,"17":101,"18":101,"19":101,"20":101,"21":101,"22":101,"23":101,"24":101,"25":101,"26":101,"27":101,"28":101,"29":95,"30":95,"31":94,"32":95,"33":6,"34":6,"35":5,"36":5,"37":1,"38":101,"39":100,"40":100,"41":100,"42":100,"43":1,"44":99,"45":99,"46":99,"47":99,"48":99,"49":99,"50":99,"51":37,"52":37,"53":37,"54":29,"55":29,"56":24,"57":29,"58":2,"59":8,"60":8,"61":3,"62":1,"63":3,"64":1,"65":37,"66":37,"67":74,"68":74,"69":37,"70":37,"71":198,"72":198,"73":198,"74":198,"75":215,"76":215,"77":215,"78":2,"79":213,"80":213,"81":823,"82":823,"83":823,"84":213,"85":610,"86":184,"87":180,"88":4,"89":180,"90":180,"91":1,"92":179,"93":78,"94":179,"95":179,"96":78,"97":0,"98":78,"99":48,"100":30,"101":78,"102":184,"103":184,"104":2,"105":182,"106":123,"107":3,"108":3,"109":3,"110":3,"111":12,"112":12,"113":3,"114":3,"115":13,"116":13,"117":13,"118":13,"119":3,"120":11,"121":78,"122":88,"123":14,"124":14,"125":78,"126":83,"127":83,"128":19,"129":19,"130":78,"131":19,"132":19,"133":19,"134":19,"135":17,"136":59,"137":2,"138":57,"139":1,"140":1,"141":1,"142":1,"143":123,"144":123,"145":123,"146":123,"147":123,"148":182,"149":182,"150":182,"151":165,"152":165,"153":91,"154":1,"155":90,"156":74,"157":17,"158":17,"159":0,"160":0,"161":123,"162":113,"163":113,"164":113,"165":90,"166":1,"167":89,"168":89,"169":90,"170":90,"171":90,"172":121,"173":117,"174":117,"175":89,"176":117,"177":82,"178":54,"179":54,"180":28,"181":28,"182":30,"183":1,"184":1,"185":66,"186":34,"187":34,"188":34,"189":0,"190":0,"191":0,"192":0,"193":34,"194":126,"195":126,"196":44,"197":44,"198":30,"199":29,"200":29,"201":29,"202":89,"203":74,"204":15,"205":15,"206":15,"207":5,"208":5,"209":5,"210":5,"211":0,"212":0,"213":0,"214":0,"215":5,"216":15,"217":28,"218":27,"219":27,"220":125,"221":125,"222":125,"223":12,"224":355,"225":355,"226":95,"227":900,"228":8,"229":134,"230":61,"231":72,"232":275,"233":3,"234":189},"f":{"0":95,"1":7,"2":1,"3":5,"4":101,"5":95,"6":95,"7":6,"8":6,"9":101,"10":99,"11":99,"12":198,"13":184,"14":180,"15":78,"16":184,"17":3,"18":78,"19":123,"20":90,"21":30,"22":126,"23":30,"24":89,"25":28,"26":125,"27":12,"28":355,"29":95,"30":900,"31":8,"32":134,"33":61,"34":72,"35":275,"36":189},"b":{"0":[95],"1":[4,91],"2":[7],"3":[1,6],"4":[0,1],"5":[5,0],"6":[101],"7":[101,98],"8":[101,99],"9":[94,1],"10":[5,1],"11":[100,1],"12":[29,8],"13":[37,12],"14":[24,5],"15":[2,27],"16":[3,5],"17":[8,3],"18":[1,2],"19":[1,2],"20":[74,62],"21":[37,37],"22":[2,213],"23":[527,296],"24":[213,610],"25":[180,4],"26":[1,179],"27":[180,177],"28":[78,101],"29":[179,104],"30":[0,78],"31":[78,77],"32":[48,30],"33":[78,77,48],"34":[2,182],"35":[123,59],"36":[182,64],"37":[1,12],"38":[14,74],"39":[88,15,14],"40":[19,64],"41":[83,19,19],"42":[19,59],"43":[78,19],"44":[17,2],"45":[19,18,17],"46":[17,0,0],"47":[2,57],"48":[59,2],"49":[1,56],"50":[57,3,3,2],"51":[2,1,1],"52":[1,0],"53":[165,17],"54":[182,165],"55":[91,74],"56":[1,90],"57":[17,0],"58":[0,0],"59":[113,0],"60":[1,89],"61":[90,89],"62":[61,28],"63":[117,4],"64":[89,28],"65":[117,89],"66":[82,35],"67":[54,28],"68":[1,27],"69":[28,28],"70":[34,0],"71":[0,0],"72":[0,0],"73":[44,82],"74":[126,44,44],"75":[29,1],"76":[30,30,30,24],"77":[74,15],"78":[15,0],"79":[15,10],"80":[5,10],"81":[5,0],"82":[0,5],"83":[0,0],"84":[27,1],"85":[28,21],"86":[125,0],"87":[125,124],"88":[355,307,306],"89":[95,94],"90":[8,6]},"meta":{"lastBranch":91,"lastFunction":37,"lastStatement":235,"seen":{"f:52:16:52:22":0,"b:52:89:52:99":0,"b:53:1:53:Infinity:undefined:undefined:undefined:undefined":1,"s:53:1:53:Infinity":0,"s:53:36:53:Infinity":1,"s:54:1:54:Infinity":2,"f:57:16:57:27":1,"b:57:93:57:103":2,"b:58:1:58:Infinity:undefined:undefined:undefined:undefined":3,"s:58:1:58:Infinity":3,"s:58:36:58:Infinity":4,"s:59:1:59:Infinity":5,"f:62:9:62:32":2,"s:63:14:63:Infinity":6,"b:65:1:66:Infinity:66:6:66:Infinity":4,"s:65:1:66:Infinity":7,"s:65:22:65:Infinity":8,"s:66:6:66:Infinity":9,"f:69:9:69:34":3,"s:70:16:70:Infinity":10,"s:71:13:71:Infinity":11,"b:73:1:74:Infinity:74:6:74:Infinity":5,"s:73:1:74:Infinity":12,"s:73:34:73:Infinity":13,"s:74:6:74:Infinity":14,"f:94:1:94:13":4,"b:94:32:94:36":6,"s:95:2:95:Infinity":15,"s:96:2:96:Infinity":16,"s:98:2:98:Infinity":17,"b:98:28:98:57:98:57:98:Infinity":7,"s:99:2:99:Infinity":18,"b:99:33:99:67:99:67:99:Infinity":8,"s:100:2:100:Infinity":19,"s:101:2:101:Infinity":20,"s:102:2:102:Infinity":21,"s:103:2:103:Infinity":22,"s:104:2:104:Infinity":23,"s:105:2:105:Infinity":24,"s:106:2:106:Infinity":25,"s:107:2:107:Infinity":26,"s:108:2:108:Infinity":27,"s:109:2:109:Infinity":28,"f:112:1:112:7":5,"s:113:2:116:Infinity":29,"f:113:30:113:36":6,"b:114:3:114:Infinity:undefined:undefined:undefined:undefined":9,"s:114:3:114:Infinity":30,"s:114:31:114:Infinity":31,"s:115:3:115:Infinity":32,"f:119:1:119:12":7,"s:120:2:127:Infinity":33,"f:120:30:120:36":8,"b:121:3:126:Infinity:124:10:126:Infinity":10,"s:121:3:126:Infinity":34,"s:122:4:122:Infinity":35,"s:123:4:123:Infinity":36,"s:125:4:125:Infinity":37,"f:130:1:130:15":9,"b:131:2:136:Infinity:136:9:136:Infinity":11,"s:131:2:136:Infinity":38,"s:132:28:132:Infinity":39,"s:133:3:133:Infinity":40,"s:134:3:134:Infinity":41,"s:135:3:135:Infinity":42,"s:136:9:136:Infinity":43,"f:139:1:139:12":10,"s:140:2:140:Infinity":44,"s:141:2:141:Infinity":45,"s:142:2:142:Infinity":46,"f:145:1:145:15":11,"s:146:28:146:Infinity":47,"s:148:34:148:Infinity":48,"s:149:2:173:Infinity":49,"s:149:15:149:18":50,"s:150:28:150:Infinity":51,"s:151:19:151:Infinity":52,"b:153:3:165:Infinity:158:10:165:Infinity":12,"s:153:3:165:Infinity":53,"b:153:7:153:36:153:36:153:66":13,"s:154:4:154:Infinity":54,"b:156:4:156:Infinity:undefined:undefined:undefined:undefined":14,"s:156:4:156:Infinity":55,"s:156:66:156:Infinity":56,"b:157:4:157:Infinity:undefined:undefined:undefined:undefined":15,"s:157:4:157:Infinity":57,"s:157:53:157:Infinity":58,"s:159:4:159:Infinity":59,"b:161:4:164:Infinity:undefined:undefined:undefined:undefined":16,"s:161:4:164:Infinity":60,"b:161:8:161:37:161:37:161:62":17,"b:162:5:162:Infinity:undefined:undefined:undefined:undefined":18,"s:162:5:162:Infinity":61,"s:162:35:162:Infinity":62,"b:163:5:163:Infinity:undefined:undefined:undefined:undefined":19,"s:163:5:163:Infinity":63,"s:163:43:163:Infinity":64,"s:167:47:167:Infinity":65,"s:168:3:172:Infinity":66,"s:169:4:169:Infinity":67,"b:169:37:169:72:169:72:169:77":20,"b:170:4:170:Infinity:undefined:undefined:undefined:undefined":21,"s:170:4:170:Infinity":68,"s:170:26:170:Infinity":69,"s:171:4:171:Infinity":70,"f:177:1:177:12":12,"s:178:26:178:Infinity":71,"s:180:32:180:Infinity":72,"s:181:2:196:Infinity":73,"s:181:15:181:18":74,"s:182:25:182:Infinity":75,"s:183:14:183:Infinity":76,"b:186:3:186:Infinity:undefined:undefined:undefined:undefined":22,"s:186:3:186:Infinity":77,"s:186:18:186:Infinity":78,"s:188:47:188:Infinity":79,"s:190:3:195:Infinity":80,"s:191:37:191:Infinity":81,"s:192:4:192:Infinity":82,"b:192:12:192:28:192:28:192:Infinity":23,"b:193:4:193:Infinity:undefined:undefined:undefined:undefined":24,"s:193:4:193:Infinity":83,"s:193:26:193:Infinity":84,"s:194:4:194:Infinity":85,"f:200:1:200:12":13,"b:201:2:202:Infinity:202:7:202:Infinity":25,"s:201:2:202:Infinity":86,"s:201:35:201:Infinity":87,"s:202:7:202:Infinity":88,"f:205:1:205:27":14,"s:206:28:206:Infinity":89,"b:208:2:208:Infinity:undefined:undefined:undefined:undefined":26,"s:208:2:208:Infinity":90,"b:208:8:208:68:208:68:208:75":27,"s:208:75:208:Infinity":91,"b:210:2:210:Infinity:undefined:undefined:undefined:undefined":28,"s:210:2:210:Infinity":92,"b:210:6:210:30:210:30:210:57":29,"s:210:57:210:Infinity":93,"s:213:2:213:Infinity":94,"s:215:2:215:Infinity":95,"f:218:1:218:17":15,"b:219:2:219:Infinity:undefined:undefined:undefined:undefined":30,"s:219:2:219:Infinity":96,"b:219:8:219:68:219:68:219:75":31,"s:219:75:219:Infinity":97,"b:221:2:224:Infinity:224:9:224:Infinity":32,"s:221:2:224:Infinity":98,"b:221:6:221:46:221:46:221:73:221:73:221:103":33,"s:223:3:223:Infinity":99,"s:224:9:224:Infinity":100,"s:226:2:226:Infinity":101,"f:229:1:229:30":16,"s:230:28:230:Infinity":102,"b:232:2:235:Infinity:235:2:235:Infinity":34,"s:232:2:235:Infinity":103,"s:234:3:234:Infinity":104,"b:235:2:235:Infinity:undefined:undefined:undefined:undefined":35,"s:235:2:235:Infinity":105,"b:235:13:235:37:235:37:235:64":36,"s:235:64:235:Infinity":106,"f:238:1:238:20":17,"s:239:63:239:Infinity":107,"s:242:34:242:Infinity":108,"s:243:2:246:Infinity":109,"s:243:15:243:18":110,"s:244:17:244:Infinity":111,"s:245:3:245:Infinity":112,"s:249:2:257:Infinity":113,"s:249:15:249:41":114,"s:250:17:250:Infinity":115,"s:251:15:251:Infinity":116,"s:252:20:252:Infinity":117,"s:256:3:256:Infinity":118,"b:256:14:256:45:256:45:256:Infinity":37,"s:260:2:260:Infinity":119,"s:260:52:260:Infinity":120,"f:263:1:263:18":18,"s:265:2:270:Infinity":121,"b:266:3:269:Infinity:undefined:undefined:undefined:undefined":38,"s:266:3:269:Infinity":122,"b:266:7:266:41:266:41:266:96:266:96:266:103":39,"s:267:4:267:Infinity":123,"s:268:4:268:Infinity":124,"s:273:2:279:Infinity":125,"s:274:25:274:Infinity":126,"b:275:3:278:Infinity:undefined:undefined:undefined:undefined":40,"s:275:3:278:Infinity":127,"b:275:7:275:35:275:35:275:91:275:91:275:98":41,"s:276:4:276:Infinity":128,"s:277:4:277:Infinity":129,"b:283:2:306:Infinity:294:2:306:Infinity":42,"s:283:2:306:Infinity":130,"b:283:6:283:26:283:26:283:46":43,"s:284:3:284:Infinity":131,"s:285:3:285:Infinity":132,"s:286:3:286:Infinity":133,"b:287:3:293:Infinity:undefined:undefined:undefined:undefined":44,"s:287:3:293:Infinity":134,"b:288:4:288:Infinity:289:4:289:Infinity:290:4:290:Infinity":45,"b:290:6:290:38:290:38:290:73:290:73:290:Infinity":46,"s:292:4:292:Infinity":135,"b:294:2:306:Infinity:296:2:306:Infinity":47,"s:294:2:306:Infinity":136,"b:294:13:294:34:294:34:294:55":48,"s:295:3:295:Infinity":137,"b:296:2:306:Infinity:undefined:undefined:undefined:undefined":49,"s:296:2:306:Infinity":138,"b:297:3:297:Infinity:298:3:298:Infinity:299:3:299:Infinity:300:3:300:Infinity":50,"b:300:5:300:37:300:37:300:72:300:72:300:Infinity":51,"s:302:3:302:Infinity":139,"s:304:16:304:Infinity":140,"b:305:3:305:Infinity:undefined:undefined:undefined:undefined":52,"s:305:3:305:Infinity":141,"s:305:13:305:Infinity":142,"f:310:1:310:18":19,"s:311:31:311:Infinity":143,"s:313:21:313:Infinity":144,"s:314:24:314:Infinity":145,"s:316:2:335:Infinity":146,"s:316:15:316:18":147,"s:317:17:317:Infinity":148,"s:318:20:318:Infinity":149,"b:320:3:334:Infinity:330:3:334:Infinity":53,"s:320:3:334:Infinity":150,"b:320:7:320:16:320:16:320:26":54,"s:321:47:321:Infinity":151,"b:323:4:329:Infinity:329:11:329:Infinity":55,"s:323:4:329:Infinity":152,"b:324:5:328:Infinity:326:12:328:Infinity":56,"s:324:5:328:Infinity":153,"s:325:6:325:Infinity":154,"s:327:6:327:Infinity":155,"s:329:11:329:Infinity":156,"b:330:3:334:Infinity:332:3:334:Infinity":57,"s:330:3:334:Infinity":157,"s:331:4:331:Infinity":158,"b:332:3:334:Infinity:undefined:undefined:undefined:undefined":58,"s:332:3:334:Infinity":159,"s:333:4:333:Infinity":160,"s:338:2:341:Infinity":161,"s:339:17:339:Infinity":162,"b:340:3:340:Infinity:undefined:undefined:undefined:undefined":59,"s:340:3:340:Infinity":163,"s:340:14:340:Infinity":164,"f:344:1:344:20":20,"b:345:2:345:Infinity:undefined:undefined:undefined:undefined":60,"s:345:2:345:Infinity":165,"b:345:8:345:69:345:69:345:76":61,"s:345:76:345:Infinity":166,"s:347:19:347:Infinity":167,"s:350:22:350:Infinity":168,"b:350:33:350:49:350:49:350:Infinity":62,"s:352:38:352:Infinity":169,"s:353:45:353:Infinity":170,"s:356:2:380:Infinity":171,"b:357:3:377:Infinity:undefined:undefined:undefined:undefined":63,"s:357:3:377:Infinity":172,"s:358:15:358:Infinity":173,"b:360:4:362:Infinity:undefined:undefined:undefined:undefined":64,"s:360:4:362:Infinity":174,"b:360:8:360:31:360:31:360:78":65,"s:361:5:361:Infinity":175,"b:364:4:376:Infinity:undefined:undefined:undefined:undefined":66,"s:364:4:376:Infinity":176,"b:365:5:375:Infinity:368:12:375:Infinity":67,"s:365:5:375:Infinity":177,"s:366:6:366:Infinity":178,"s:367:6:367:Infinity":179,"s:369:27:369:Infinity":180,"b:371:6:374:Infinity:undefined:undefined:undefined:undefined":68,"s:371:6:374:Infinity":181,"b:371:10:371:26:371:26:371:74":69,"f:371:43:371:44":21,"s:371:51:371:71":182,"s:372:7:372:Infinity":183,"s:373:7:373:Infinity":184,"s:379:3:379:Infinity":185,"b:382:2:391:Infinity:385:9:391:Infinity":70,"s:382:2:391:Infinity":186,"s:383:3:383:Infinity":187,"s:384:3:384:Infinity":188,"s:386:19:386:Infinity":189,"b:387:3:390:Infinity:undefined:undefined:undefined:undefined":71,"s:387:3:390:Infinity":190,"b:387:7:387:43:387:43:387:49":72,"s:388:4:388:Infinity":191,"s:389:4:389:Infinity":192,"s:393:2:393:Infinity":193,"f:396:1:396:52":22,"s:397:24:397:Infinity":194,"b:399:2:402:Infinity:undefined:undefined:undefined:undefined":73,"s:399:2:402:Infinity":195,"b:399:6:399:37:399:37:399:100:399:100:399:107":74,"s:400:3:400:Infinity":196,"s:401:3:401:Infinity":197,"f:405:1:405:14":23,"b:406:2:410:Infinity:undefined:undefined:undefined:undefined":75,"s:406:2:410:Infinity":198,"b:406:7:406:42:406:42:406:52:406:52:406:88:406:88:406:95":76,"s:407:3:407:Infinity":199,"s:408:3:408:Infinity":200,"s:409:3:409:Infinity":201,"f:413:1:413:15":24,"b:414:2:414:Infinity:undefined:undefined:undefined:undefined":77,"s:414:2:414:Infinity":202,"s:414:31:414:Infinity":203,"b:416:2:433:Infinity:undefined:undefined:undefined:undefined":78,"s:416:2:433:Infinity":204,"s:417:23:417:Infinity":205,"b:417:23:417:55:417:55:417:Infinity":79,"b:419:3:432:Infinity:undefined:undefined:undefined:undefined":80,"s:419:3:432:Infinity":206,"s:420:23:420:Infinity":207,"s:422:4:431:Infinity":208,"s:423:37:423:Infinity":209,"b:423:37:423:77:423:77:423:Infinity":81,"b:425:5:430:Infinity:430:12:430:Infinity":82,"s:425:5:430:Infinity":210,"s:426:6:426:Infinity":211,"b:428:6:428:Infinity:undefined:undefined:undefined:undefined":83,"s:428:6:428:Infinity":212,"s:428:43:428:Infinity":213,"s:429:6:429:Infinity":214,"s:430:12:430:Infinity":215,"s:435:2:435:Infinity":216,"f:438:1:438:14":25,"b:439:2:442:Infinity:undefined:undefined:undefined:undefined":84,"s:439:2:442:Infinity":217,"b:439:6:439:42:439:42:439:48":85,"s:440:3:440:Infinity":218,"s:441:3:441:Infinity":219,"f:445:1:445:13":26,"b:446:2:449:Infinity:undefined:undefined:undefined:undefined":86,"s:446:2:449:Infinity":220,"b:446:6:446:41:446:41:446:47":87,"s:447:3:447:Infinity":221,"s:448:3:448:Infinity":222,"f:453:9:453:38":27,"s:454:1:454:Infinity":223,"f:457:9:457:31":28,"s:458:16:458:Infinity":224,"s:459:1:459:Infinity":225,"b:459:8:459:24:459:24:459:40:459:40:459:Infinity":88,"f:462:9:462:26":29,"s:463:1:463:Infinity":226,"b:463:8:463:33:463:33:463:Infinity":89,"f:468:9:468:19":30,"s:469:1:469:Infinity":227,"f:474:9:474:17":31,"s:475:1:475:Infinity":228,"b:475:8:475:41:475:41:475:Infinity":90,"f:480:9:480:17":32,"s:481:1:481:Infinity":229,"f:486:9:486:18":33,"s:487:1:487:Infinity":230,"f:492:9:492:20":34,"s:493:1:493:Infinity":231,"f:498:9:498:16":35,"s:499:1:499:Infinity":232,"s:502:24:502:Infinity":233,"f:506:9:506:22":36,"s:507:1:507:Infinity":234}}} 2 - }
coverage/favicon.png

This is a binary file and will not be displayed.

-116
coverage/index.html
··· 1 - 2 - <!doctype html> 3 - <html lang="en"> 4 - 5 - <head> 6 - <title>Code coverage report for All files</title> 7 - <meta charset="utf-8" /> 8 - <link rel="stylesheet" href="prettify.css" /> 9 - <link rel="stylesheet" href="base.css" /> 10 - <link rel="shortcut icon" type="image/x-icon" href="favicon.png" /> 11 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 12 - <style type='text/css'> 13 - .coverage-summary .sorter { 14 - background-image: url(sort-arrow-sprite.png); 15 - } 16 - </style> 17 - </head> 18 - 19 - <body> 20 - <div class='wrapper'> 21 - <div class='pad1'> 22 - <h1>All files</h1> 23 - <div class='clearfix'> 24 - 25 - <div class='fl pad1y space-right2'> 26 - <span class="strong">94.46% </span> 27 - <span class="quiet">Statements</span> 28 - <span class='fraction'>222/235</span> 29 - </div> 30 - 31 - 32 - <div class='fl pad1y space-right2'> 33 - <span class="strong">89% </span> 34 - <span class="quiet">Branches</span> 35 - <span class='fraction'>170/191</span> 36 - </div> 37 - 38 - 39 - <div class='fl pad1y space-right2'> 40 - <span class="strong">100% </span> 41 - <span class="quiet">Functions</span> 42 - <span class='fraction'>37/37</span> 43 - </div> 44 - 45 - 46 - <div class='fl pad1y space-right2'> 47 - <span class="strong">95.14% </span> 48 - <span class="quiet">Lines</span> 49 - <span class='fraction'>196/206</span> 50 - </div> 51 - 52 - 53 - </div> 54 - <p class="quiet"> 55 - Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block. 56 - </p> 57 - <template id="filterTemplate"> 58 - <div class="quiet"> 59 - Filter: 60 - <input type="search" id="fileSearch"> 61 - </div> 62 - </template> 63 - </div> 64 - <div class='status-line high'></div> 65 - <div class="pad1"> 66 - <table class="coverage-summary"> 67 - <thead> 68 - <tr> 69 - <th data-col="file" data-fmt="html" data-html="true" class="file">File</th> 70 - <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th> 71 - <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th> 72 - <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th> 73 - <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th> 74 - <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th> 75 - <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th> 76 - <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th> 77 - <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th> 78 - <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th> 79 - </tr> 80 - </thead> 81 - <tbody><tr> 82 - <td class="file high" data-value="morphlex.ts"><a href="morphlex.ts.html">morphlex.ts</a></td> 83 - <td data-value="94.46" class="pic high"> 84 - <div class="chart"><div class="cover-fill" style="width: 94%"></div><div class="cover-empty" style="width: 6%"></div></div> 85 - </td> 86 - <td data-value="94.46" class="pct high">94.46%</td> 87 - <td data-value="235" class="abs high">222/235</td> 88 - <td data-value="89" class="pct high">89%</td> 89 - <td data-value="191" class="abs high">170/191</td> 90 - <td data-value="100" class="pct high">100%</td> 91 - <td data-value="37" class="abs high">37/37</td> 92 - <td data-value="95.14" class="pct high">95.14%</td> 93 - <td data-value="206" class="abs high">196/206</td> 94 - </tr> 95 - 96 - </tbody> 97 - </table> 98 - </div> 99 - <div class='push'></div><!-- for sticky footer --> 100 - </div><!-- /wrapper --> 101 - <div class='footer quiet pad2 space-top1 center small'> 102 - Code coverage generated by 103 - <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> 104 - at 2025-10-30T21:26:27.959Z 105 - </div> 106 - <script src="prettify.js"></script> 107 - <script> 108 - window.onload = function () { 109 - prettyPrint(); 110 - }; 111 - </script> 112 - <script src="sorter.js"></script> 113 - <script src="block-navigation.js"></script> 114 - </body> 115 - </html> 116 -
-1609
coverage/morphlex.ts.html
··· 1 - 2 - <!doctype html> 3 - <html lang="en"> 4 - 5 - <head> 6 - <title>Code coverage report for morphlex.ts</title> 7 - <meta charset="utf-8" /> 8 - <link rel="stylesheet" href="prettify.css" /> 9 - <link rel="stylesheet" href="base.css" /> 10 - <link rel="shortcut icon" type="image/x-icon" href="favicon.png" /> 11 - <meta name="viewport" content="width=device-width, initial-scale=1" /> 12 - <style type='text/css'> 13 - .coverage-summary .sorter { 14 - background-image: url(sort-arrow-sprite.png); 15 - } 16 - </style> 17 - </head> 18 - 19 - <body> 20 - <div class='wrapper'> 21 - <div class='pad1'> 22 - <h1><a href="index.html">All files</a> morphlex.ts</h1> 23 - <div class='clearfix'> 24 - 25 - <div class='fl pad1y space-right2'> 26 - <span class="strong">94.46% </span> 27 - <span class="quiet">Statements</span> 28 - <span class='fraction'>222/235</span> 29 - </div> 30 - 31 - 32 - <div class='fl pad1y space-right2'> 33 - <span class="strong">89% </span> 34 - <span class="quiet">Branches</span> 35 - <span class='fraction'>170/191</span> 36 - </div> 37 - 38 - 39 - <div class='fl pad1y space-right2'> 40 - <span class="strong">100% </span> 41 - <span class="quiet">Functions</span> 42 - <span class='fraction'>37/37</span> 43 - </div> 44 - 45 - 46 - <div class='fl pad1y space-right2'> 47 - <span class="strong">95.14% </span> 48 - <span class="quiet">Lines</span> 49 - <span class='fraction'>196/206</span> 50 - </div> 51 - 52 - 53 - </div> 54 - <p class="quiet"> 55 - Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block. 56 - </p> 57 - <template id="filterTemplate"> 58 - <div class="quiet"> 59 - Filter: 60 - <input type="search" id="fileSearch"> 61 - </div> 62 - </template> 63 - </div> 64 - <div class='status-line high'></div> 65 - <pre><table class="coverage"> 66 - <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a> 67 - <a name='L2'></a><a href='#L2'>2</a> 68 - <a name='L3'></a><a href='#L3'>3</a> 69 - <a name='L4'></a><a href='#L4'>4</a> 70 - <a name='L5'></a><a href='#L5'>5</a> 71 - <a name='L6'></a><a href='#L6'>6</a> 72 - <a name='L7'></a><a href='#L7'>7</a> 73 - <a name='L8'></a><a href='#L8'>8</a> 74 - <a name='L9'></a><a href='#L9'>9</a> 75 - <a name='L10'></a><a href='#L10'>10</a> 76 - <a name='L11'></a><a href='#L11'>11</a> 77 - <a name='L12'></a><a href='#L12'>12</a> 78 - <a name='L13'></a><a href='#L13'>13</a> 79 - <a name='L14'></a><a href='#L14'>14</a> 80 - <a name='L15'></a><a href='#L15'>15</a> 81 - <a name='L16'></a><a href='#L16'>16</a> 82 - <a name='L17'></a><a href='#L17'>17</a> 83 - <a name='L18'></a><a href='#L18'>18</a> 84 - <a name='L19'></a><a href='#L19'>19</a> 85 - <a name='L20'></a><a href='#L20'>20</a> 86 - <a name='L21'></a><a href='#L21'>21</a> 87 - <a name='L22'></a><a href='#L22'>22</a> 88 - <a name='L23'></a><a href='#L23'>23</a> 89 - <a name='L24'></a><a href='#L24'>24</a> 90 - <a name='L25'></a><a href='#L25'>25</a> 91 - <a name='L26'></a><a href='#L26'>26</a> 92 - <a name='L27'></a><a href='#L27'>27</a> 93 - <a name='L28'></a><a href='#L28'>28</a> 94 - <a name='L29'></a><a href='#L29'>29</a> 95 - <a name='L30'></a><a href='#L30'>30</a> 96 - <a name='L31'></a><a href='#L31'>31</a> 97 - <a name='L32'></a><a href='#L32'>32</a> 98 - <a name='L33'></a><a href='#L33'>33</a> 99 - <a name='L34'></a><a href='#L34'>34</a> 100 - <a name='L35'></a><a href='#L35'>35</a> 101 - <a name='L36'></a><a href='#L36'>36</a> 102 - <a name='L37'></a><a href='#L37'>37</a> 103 - <a name='L38'></a><a href='#L38'>38</a> 104 - <a name='L39'></a><a href='#L39'>39</a> 105 - <a name='L40'></a><a href='#L40'>40</a> 106 - <a name='L41'></a><a href='#L41'>41</a> 107 - <a name='L42'></a><a href='#L42'>42</a> 108 - <a name='L43'></a><a href='#L43'>43</a> 109 - <a name='L44'></a><a href='#L44'>44</a> 110 - <a name='L45'></a><a href='#L45'>45</a> 111 - <a name='L46'></a><a href='#L46'>46</a> 112 - <a name='L47'></a><a href='#L47'>47</a> 113 - <a name='L48'></a><a href='#L48'>48</a> 114 - <a name='L49'></a><a href='#L49'>49</a> 115 - <a name='L50'></a><a href='#L50'>50</a> 116 - <a name='L51'></a><a href='#L51'>51</a> 117 - <a name='L52'></a><a href='#L52'>52</a> 118 - <a name='L53'></a><a href='#L53'>53</a> 119 - <a name='L54'></a><a href='#L54'>54</a> 120 - <a name='L55'></a><a href='#L55'>55</a> 121 - <a name='L56'></a><a href='#L56'>56</a> 122 - <a name='L57'></a><a href='#L57'>57</a> 123 - <a name='L58'></a><a href='#L58'>58</a> 124 - <a name='L59'></a><a href='#L59'>59</a> 125 - <a name='L60'></a><a href='#L60'>60</a> 126 - <a name='L61'></a><a href='#L61'>61</a> 127 - <a name='L62'></a><a href='#L62'>62</a> 128 - <a name='L63'></a><a href='#L63'>63</a> 129 - <a name='L64'></a><a href='#L64'>64</a> 130 - <a name='L65'></a><a href='#L65'>65</a> 131 - <a name='L66'></a><a href='#L66'>66</a> 132 - <a name='L67'></a><a href='#L67'>67</a> 133 - <a name='L68'></a><a href='#L68'>68</a> 134 - <a name='L69'></a><a href='#L69'>69</a> 135 - <a name='L70'></a><a href='#L70'>70</a> 136 - <a name='L71'></a><a href='#L71'>71</a> 137 - <a name='L72'></a><a href='#L72'>72</a> 138 - <a name='L73'></a><a href='#L73'>73</a> 139 - <a name='L74'></a><a href='#L74'>74</a> 140 - <a name='L75'></a><a href='#L75'>75</a> 141 - <a name='L76'></a><a href='#L76'>76</a> 142 - <a name='L77'></a><a href='#L77'>77</a> 143 - <a name='L78'></a><a href='#L78'>78</a> 144 - <a name='L79'></a><a href='#L79'>79</a> 145 - <a name='L80'></a><a href='#L80'>80</a> 146 - <a name='L81'></a><a href='#L81'>81</a> 147 - <a name='L82'></a><a href='#L82'>82</a> 148 - <a name='L83'></a><a href='#L83'>83</a> 149 - <a name='L84'></a><a href='#L84'>84</a> 150 - <a name='L85'></a><a href='#L85'>85</a> 151 - <a name='L86'></a><a href='#L86'>86</a> 152 - <a name='L87'></a><a href='#L87'>87</a> 153 - <a name='L88'></a><a href='#L88'>88</a> 154 - <a name='L89'></a><a href='#L89'>89</a> 155 - <a name='L90'></a><a href='#L90'>90</a> 156 - <a name='L91'></a><a href='#L91'>91</a> 157 - <a name='L92'></a><a href='#L92'>92</a> 158 - <a name='L93'></a><a href='#L93'>93</a> 159 - <a name='L94'></a><a href='#L94'>94</a> 160 - <a name='L95'></a><a href='#L95'>95</a> 161 - <a name='L96'></a><a href='#L96'>96</a> 162 - <a name='L97'></a><a href='#L97'>97</a> 163 - <a name='L98'></a><a href='#L98'>98</a> 164 - <a name='L99'></a><a href='#L99'>99</a> 165 - <a name='L100'></a><a href='#L100'>100</a> 166 - <a name='L101'></a><a href='#L101'>101</a> 167 - <a name='L102'></a><a href='#L102'>102</a> 168 - <a name='L103'></a><a href='#L103'>103</a> 169 - <a name='L104'></a><a href='#L104'>104</a> 170 - <a name='L105'></a><a href='#L105'>105</a> 171 - <a name='L106'></a><a href='#L106'>106</a> 172 - <a name='L107'></a><a href='#L107'>107</a> 173 - <a name='L108'></a><a href='#L108'>108</a> 174 - <a name='L109'></a><a href='#L109'>109</a> 175 - <a name='L110'></a><a href='#L110'>110</a> 176 - <a name='L111'></a><a href='#L111'>111</a> 177 - <a name='L112'></a><a href='#L112'>112</a> 178 - <a name='L113'></a><a href='#L113'>113</a> 179 - <a name='L114'></a><a href='#L114'>114</a> 180 - <a name='L115'></a><a href='#L115'>115</a> 181 - <a name='L116'></a><a href='#L116'>116</a> 182 - <a name='L117'></a><a href='#L117'>117</a> 183 - <a name='L118'></a><a href='#L118'>118</a> 184 - <a name='L119'></a><a href='#L119'>119</a> 185 - <a name='L120'></a><a href='#L120'>120</a> 186 - <a name='L121'></a><a href='#L121'>121</a> 187 - <a name='L122'></a><a href='#L122'>122</a> 188 - <a name='L123'></a><a href='#L123'>123</a> 189 - <a name='L124'></a><a href='#L124'>124</a> 190 - <a name='L125'></a><a href='#L125'>125</a> 191 - <a name='L126'></a><a href='#L126'>126</a> 192 - <a name='L127'></a><a href='#L127'>127</a> 193 - <a name='L128'></a><a href='#L128'>128</a> 194 - <a name='L129'></a><a href='#L129'>129</a> 195 - <a name='L130'></a><a href='#L130'>130</a> 196 - <a name='L131'></a><a href='#L131'>131</a> 197 - <a name='L132'></a><a href='#L132'>132</a> 198 - <a name='L133'></a><a href='#L133'>133</a> 199 - <a name='L134'></a><a href='#L134'>134</a> 200 - <a name='L135'></a><a href='#L135'>135</a> 201 - <a name='L136'></a><a href='#L136'>136</a> 202 - <a name='L137'></a><a href='#L137'>137</a> 203 - <a name='L138'></a><a href='#L138'>138</a> 204 - <a name='L139'></a><a href='#L139'>139</a> 205 - <a name='L140'></a><a href='#L140'>140</a> 206 - <a name='L141'></a><a href='#L141'>141</a> 207 - <a name='L142'></a><a href='#L142'>142</a> 208 - <a name='L143'></a><a href='#L143'>143</a> 209 - <a name='L144'></a><a href='#L144'>144</a> 210 - <a name='L145'></a><a href='#L145'>145</a> 211 - <a name='L146'></a><a href='#L146'>146</a> 212 - <a name='L147'></a><a href='#L147'>147</a> 213 - <a name='L148'></a><a href='#L148'>148</a> 214 - <a name='L149'></a><a href='#L149'>149</a> 215 - <a name='L150'></a><a href='#L150'>150</a> 216 - <a name='L151'></a><a href='#L151'>151</a> 217 - <a name='L152'></a><a href='#L152'>152</a> 218 - <a name='L153'></a><a href='#L153'>153</a> 219 - <a name='L154'></a><a href='#L154'>154</a> 220 - <a name='L155'></a><a href='#L155'>155</a> 221 - <a name='L156'></a><a href='#L156'>156</a> 222 - <a name='L157'></a><a href='#L157'>157</a> 223 - <a name='L158'></a><a href='#L158'>158</a> 224 - <a name='L159'></a><a href='#L159'>159</a> 225 - <a name='L160'></a><a href='#L160'>160</a> 226 - <a name='L161'></a><a href='#L161'>161</a> 227 - <a name='L162'></a><a href='#L162'>162</a> 228 - <a name='L163'></a><a href='#L163'>163</a> 229 - <a name='L164'></a><a href='#L164'>164</a> 230 - <a name='L165'></a><a href='#L165'>165</a> 231 - <a name='L166'></a><a href='#L166'>166</a> 232 - <a name='L167'></a><a href='#L167'>167</a> 233 - <a name='L168'></a><a href='#L168'>168</a> 234 - <a name='L169'></a><a href='#L169'>169</a> 235 - <a name='L170'></a><a href='#L170'>170</a> 236 - <a name='L171'></a><a href='#L171'>171</a> 237 - <a name='L172'></a><a href='#L172'>172</a> 238 - <a name='L173'></a><a href='#L173'>173</a> 239 - <a name='L174'></a><a href='#L174'>174</a> 240 - <a name='L175'></a><a href='#L175'>175</a> 241 - <a name='L176'></a><a href='#L176'>176</a> 242 - <a name='L177'></a><a href='#L177'>177</a> 243 - <a name='L178'></a><a href='#L178'>178</a> 244 - <a name='L179'></a><a href='#L179'>179</a> 245 - <a name='L180'></a><a href='#L180'>180</a> 246 - <a name='L181'></a><a href='#L181'>181</a> 247 - <a name='L182'></a><a href='#L182'>182</a> 248 - <a name='L183'></a><a href='#L183'>183</a> 249 - <a name='L184'></a><a href='#L184'>184</a> 250 - <a name='L185'></a><a href='#L185'>185</a> 251 - <a name='L186'></a><a href='#L186'>186</a> 252 - <a name='L187'></a><a href='#L187'>187</a> 253 - <a name='L188'></a><a href='#L188'>188</a> 254 - <a name='L189'></a><a href='#L189'>189</a> 255 - <a name='L190'></a><a href='#L190'>190</a> 256 - <a name='L191'></a><a href='#L191'>191</a> 257 - <a name='L192'></a><a href='#L192'>192</a> 258 - <a name='L193'></a><a href='#L193'>193</a> 259 - <a name='L194'></a><a href='#L194'>194</a> 260 - <a name='L195'></a><a href='#L195'>195</a> 261 - <a name='L196'></a><a href='#L196'>196</a> 262 - <a name='L197'></a><a href='#L197'>197</a> 263 - <a name='L198'></a><a href='#L198'>198</a> 264 - <a name='L199'></a><a href='#L199'>199</a> 265 - <a name='L200'></a><a href='#L200'>200</a> 266 - <a name='L201'></a><a href='#L201'>201</a> 267 - <a name='L202'></a><a href='#L202'>202</a> 268 - <a name='L203'></a><a href='#L203'>203</a> 269 - <a name='L204'></a><a href='#L204'>204</a> 270 - <a name='L205'></a><a href='#L205'>205</a> 271 - <a name='L206'></a><a href='#L206'>206</a> 272 - <a name='L207'></a><a href='#L207'>207</a> 273 - <a name='L208'></a><a href='#L208'>208</a> 274 - <a name='L209'></a><a href='#L209'>209</a> 275 - <a name='L210'></a><a href='#L210'>210</a> 276 - <a name='L211'></a><a href='#L211'>211</a> 277 - <a name='L212'></a><a href='#L212'>212</a> 278 - <a name='L213'></a><a href='#L213'>213</a> 279 - <a name='L214'></a><a href='#L214'>214</a> 280 - <a name='L215'></a><a href='#L215'>215</a> 281 - <a name='L216'></a><a href='#L216'>216</a> 282 - <a name='L217'></a><a href='#L217'>217</a> 283 - <a name='L218'></a><a href='#L218'>218</a> 284 - <a name='L219'></a><a href='#L219'>219</a> 285 - <a name='L220'></a><a href='#L220'>220</a> 286 - <a name='L221'></a><a href='#L221'>221</a> 287 - <a name='L222'></a><a href='#L222'>222</a> 288 - <a name='L223'></a><a href='#L223'>223</a> 289 - <a name='L224'></a><a href='#L224'>224</a> 290 - <a name='L225'></a><a href='#L225'>225</a> 291 - <a name='L226'></a><a href='#L226'>226</a> 292 - <a name='L227'></a><a href='#L227'>227</a> 293 - <a name='L228'></a><a href='#L228'>228</a> 294 - <a name='L229'></a><a href='#L229'>229</a> 295 - <a name='L230'></a><a href='#L230'>230</a> 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></td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span> 575 - <span class="cline-any cline-neutral">&nbsp;</span> 576 - <span class="cline-any cline-neutral">&nbsp;</span> 577 - <span class="cline-any cline-neutral">&nbsp;</span> 578 - <span class="cline-any cline-neutral">&nbsp;</span> 579 - <span class="cline-any cline-neutral">&nbsp;</span> 580 - <span class="cline-any cline-neutral">&nbsp;</span> 581 - <span class="cline-any cline-neutral">&nbsp;</span> 582 - <span class="cline-any cline-neutral">&nbsp;</span> 583 - <span class="cline-any cline-neutral">&nbsp;</span> 584 - <span class="cline-any cline-neutral">&nbsp;</span> 585 - <span class="cline-any cline-neutral">&nbsp;</span> 586 - <span class="cline-any cline-neutral">&nbsp;</span> 587 - <span class="cline-any cline-neutral">&nbsp;</span> 588 - <span class="cline-any cline-neutral">&nbsp;</span> 589 - <span class="cline-any cline-neutral">&nbsp;</span> 590 - <span class="cline-any cline-neutral">&nbsp;</span> 591 - <span class="cline-any cline-neutral">&nbsp;</span> 592 - <span class="cline-any cline-neutral">&nbsp;</span> 593 - <span class="cline-any cline-neutral">&nbsp;</span> 594 - <span class="cline-any cline-neutral">&nbsp;</span> 595 - <span class="cline-any cline-neutral">&nbsp;</span> 596 - <span class="cline-any cline-neutral">&nbsp;</span> 597 - <span class="cline-any cline-neutral">&nbsp;</span> 598 - <span class="cline-any cline-neutral">&nbsp;</span> 599 - <span class="cline-any cline-neutral">&nbsp;</span> 600 - <span class="cline-any cline-neutral">&nbsp;</span> 601 - <span class="cline-any cline-neutral">&nbsp;</span> 602 - <span class="cline-any cline-neutral">&nbsp;</span> 603 - <span class="cline-any cline-neutral">&nbsp;</span> 604 - <span class="cline-any cline-neutral">&nbsp;</span> 605 - <span class="cline-any cline-neutral">&nbsp;</span> 606 - <span class="cline-any cline-neutral">&nbsp;</span> 607 - <span class="cline-any cline-neutral">&nbsp;</span> 608 - <span class="cline-any cline-neutral">&nbsp;</span> 609 - <span class="cline-any cline-neutral">&nbsp;</span> 610 - <span class="cline-any cline-neutral">&nbsp;</span> 611 - <span class="cline-any cline-neutral">&nbsp;</span> 612 - <span class="cline-any cline-neutral">&nbsp;</span> 613 - <span class="cline-any cline-neutral">&nbsp;</span> 614 - <span class="cline-any cline-neutral">&nbsp;</span> 615 - <span class="cline-any cline-neutral">&nbsp;</span> 616 - <span class="cline-any cline-neutral">&nbsp;</span> 617 - <span class="cline-any cline-neutral">&nbsp;</span> 618 - <span class="cline-any cline-neutral">&nbsp;</span> 619 - <span class="cline-any cline-neutral">&nbsp;</span> 620 - <span class="cline-any cline-neutral">&nbsp;</span> 621 - <span class="cline-any cline-neutral">&nbsp;</span> 622 - <span class="cline-any cline-neutral">&nbsp;</span> 623 - <span class="cline-any cline-neutral">&nbsp;</span> 624 - <span class="cline-any cline-neutral">&nbsp;</span> 625 - <span class="cline-any cline-neutral">&nbsp;</span> 626 - <span class="cline-any cline-yes">95x</span> 627 - <span class="cline-any cline-yes">95x</span> 628 - <span class="cline-any cline-neutral">&nbsp;</span> 629 - <span class="cline-any cline-neutral">&nbsp;</span> 630 - <span class="cline-any cline-neutral">&nbsp;</span> 631 - <span class="cline-any cline-yes">7x</span> 632 - <span class="cline-any cline-yes">6x</span> 633 - <span class="cline-any cline-neutral">&nbsp;</span> 634 - <span class="cline-any cline-neutral">&nbsp;</span> 635 - <span class="cline-any cline-neutral">&nbsp;</span> 636 - <span class="cline-any cline-yes">1x</span> 637 - <span class="cline-any cline-neutral">&nbsp;</span> 638 - <span class="cline-any cline-yes">1x</span> 639 - <span class="cline-any cline-yes">1x</span> 640 - <span class="cline-any cline-neutral">&nbsp;</span> 641 - <span class="cline-any cline-neutral">&nbsp;</span> 642 - <span class="cline-any cline-neutral">&nbsp;</span> 643 - <span class="cline-any cline-yes">5x</span> 644 - <span class="cline-any cline-yes">5x</span> 645 - <span class="cline-any cline-neutral">&nbsp;</span> 646 - <span class="cline-any cline-yes">5x</span> 647 - <span class="cline-any cline-no">&nbsp;</span> 648 - <span class="cline-any cline-neutral">&nbsp;</span> 649 - <span class="cline-any cline-neutral">&nbsp;</span> 650 - <span class="cline-any cline-neutral">&nbsp;</span> 651 - <span class="cline-any cline-neutral">&nbsp;</span> 652 - <span class="cline-any cline-neutral">&nbsp;</span> 653 - <span class="cline-any cline-neutral">&nbsp;</span> 654 - <span class="cline-any cline-neutral">&nbsp;</span> 655 - <span class="cline-any cline-neutral">&nbsp;</span> 656 - <span class="cline-any cline-neutral">&nbsp;</span> 657 - <span class="cline-any cline-neutral">&nbsp;</span> 658 - <span class="cline-any cline-neutral">&nbsp;</span> 659 - <span class="cline-any cline-neutral">&nbsp;</span> 660 - <span class="cline-any cline-neutral">&nbsp;</span> 661 - <span class="cline-any cline-neutral">&nbsp;</span> 662 - <span class="cline-any cline-neutral">&nbsp;</span> 663 - <span class="cline-any cline-neutral">&nbsp;</span> 664 - <span class="cline-any cline-neutral">&nbsp;</span> 665 - <span class="cline-any cline-neutral">&nbsp;</span> 666 - <span class="cline-any cline-neutral">&nbsp;</span> 667 - <span class="cline-any cline-neutral">&nbsp;</span> 668 - <span class="cline-any cline-yes">101x</span> 669 - <span class="cline-any cline-yes">101x</span> 670 - <span class="cline-any cline-neutral">&nbsp;</span> 671 - <span class="cline-any cline-yes">101x</span> 672 - <span class="cline-any cline-yes">101x</span> 673 - <span class="cline-any cline-yes">101x</span> 674 - <span class="cline-any cline-yes">101x</span> 675 - <span class="cline-any cline-yes">101x</span> 676 - <span class="cline-any cline-yes">101x</span> 677 - <span class="cline-any cline-yes">101x</span> 678 - <span class="cline-any cline-yes">101x</span> 679 - <span class="cline-any cline-yes">101x</span> 680 - <span class="cline-any cline-yes">101x</span> 681 - <span class="cline-any cline-yes">101x</span> 682 - <span class="cline-any cline-yes">101x</span> 683 - <span class="cline-any cline-neutral">&nbsp;</span> 684 - <span class="cline-any cline-neutral">&nbsp;</span> 685 - <span class="cline-any cline-neutral">&nbsp;</span> 686 - <span class="cline-any cline-yes">95x</span> 687 - <span class="cline-any cline-yes">95x</span> 688 - <span class="cline-any cline-yes">95x</span> 689 - <span class="cline-any cline-neutral">&nbsp;</span> 690 - <span class="cline-any cline-neutral">&nbsp;</span> 691 - <span class="cline-any cline-neutral">&nbsp;</span> 692 - <span class="cline-any cline-neutral">&nbsp;</span> 693 - <span class="cline-any cline-yes">6x</span> 694 - <span class="cline-any cline-yes">6x</span> 695 - <span class="cline-any cline-yes">5x</span> 696 - <span class="cline-any cline-yes">5x</span> 697 - <span class="cline-any cline-neutral">&nbsp;</span> 698 - <span class="cline-any cline-yes">1x</span> 699 - <span class="cline-any cline-neutral">&nbsp;</span> 700 - <span class="cline-any cline-neutral">&nbsp;</span> 701 - <span class="cline-any cline-neutral">&nbsp;</span> 702 - <span class="cline-any cline-neutral">&nbsp;</span> 703 - <span class="cline-any cline-neutral">&nbsp;</span> 704 - <span class="cline-any cline-yes">101x</span> 705 - <span class="cline-any cline-yes">100x</span> 706 - <span class="cline-any cline-yes">100x</span> 707 - <span class="cline-any cline-yes">100x</span> 708 - <span class="cline-any cline-yes">100x</span> 709 - <span class="cline-any cline-yes">1x</span> 710 - <span class="cline-any cline-neutral">&nbsp;</span> 711 - <span class="cline-any cline-neutral">&nbsp;</span> 712 - <span class="cline-any cline-neutral">&nbsp;</span> 713 - <span class="cline-any cline-yes">99x</span> 714 - <span class="cline-any cline-yes">99x</span> 715 - <span class="cline-any cline-yes">99x</span> 716 - <span class="cline-any cline-neutral">&nbsp;</span> 717 - <span class="cline-any cline-neutral">&nbsp;</span> 718 - <span class="cline-any cline-neutral">&nbsp;</span> 719 - <span class="cline-any cline-yes">99x</span> 720 - <span class="cline-any cline-neutral">&nbsp;</span> 721 - <span class="cline-any cline-yes">99x</span> 722 - <span class="cline-any cline-yes">99x</span> 723 - <span class="cline-any cline-yes">37x</span> 724 - <span class="cline-any cline-yes">37x</span> 725 - <span class="cline-any cline-neutral">&nbsp;</span> 726 - <span class="cline-any cline-yes">37x</span> 727 - <span class="cline-any cline-yes">29x</span> 728 - <span class="cline-any cline-neutral">&nbsp;</span> 729 - <span class="cline-any cline-yes">29x</span> 730 - <span class="cline-any cline-yes">29x</span> 731 - <span class="cline-any cline-neutral">&nbsp;</span> 732 - <span class="cline-any cline-yes">8x</span> 733 - <span class="cline-any cline-neutral">&nbsp;</span> 734 - <span class="cline-any cline-yes">8x</span> 735 - <span class="cline-any cline-yes">3x</span> 736 - <span class="cline-any cline-yes">3x</span> 737 - <span class="cline-any cline-neutral">&nbsp;</span> 738 - <span class="cline-any cline-neutral">&nbsp;</span> 739 - <span class="cline-any cline-neutral">&nbsp;</span> 740 - <span class="cline-any cline-yes">37x</span> 741 - <span class="cline-any cline-yes">37x</span> 742 - <span class="cline-any cline-yes">74x</span> 743 - <span class="cline-any cline-yes">74x</span> 744 - <span class="cline-any cline-yes">37x</span> 745 - <span class="cline-any cline-neutral">&nbsp;</span> 746 - <span class="cline-any cline-neutral">&nbsp;</span> 747 - <span class="cline-any cline-neutral">&nbsp;</span> 748 - <span class="cline-any cline-neutral">&nbsp;</span> 749 - <span class="cline-any cline-neutral">&nbsp;</span> 750 - <span class="cline-any cline-neutral">&nbsp;</span> 751 - <span class="cline-any cline-yes">198x</span> 752 - <span class="cline-any cline-neutral">&nbsp;</span> 753 - <span class="cline-any cline-yes">198x</span> 754 - <span class="cline-any cline-yes">198x</span> 755 - <span class="cline-any cline-yes">215x</span> 756 - <span class="cline-any cline-yes">215x</span> 757 - <span class="cline-any cline-neutral">&nbsp;</span> 758 - <span class="cline-any cline-neutral">&nbsp;</span> 759 - <span class="cline-any cline-yes">215x</span> 760 - <span class="cline-any cline-neutral">&nbsp;</span> 761 - <span class="cline-any cline-yes">213x</span> 762 - <span class="cline-any cline-neutral">&nbsp;</span> 763 - <span class="cline-any cline-yes">213x</span> 764 - <span class="cline-any cline-yes">823x</span> 765 - <span class="cline-any cline-yes">823x</span> 766 - <span class="cline-any cline-yes">823x</span> 767 - <span class="cline-any cline-yes">610x</span> 768 - <span class="cline-any cline-neutral">&nbsp;</span> 769 - <span class="cline-any cline-neutral">&nbsp;</span> 770 - <span class="cline-any cline-neutral">&nbsp;</span> 771 - <span class="cline-any cline-neutral">&nbsp;</span> 772 - <span class="cline-any cline-neutral">&nbsp;</span> 773 - <span class="cline-any cline-neutral">&nbsp;</span> 774 - <span class="cline-any cline-yes">184x</span> 775 - <span class="cline-any cline-yes">4x</span> 776 - <span class="cline-any cline-neutral">&nbsp;</span> 777 - <span class="cline-any cline-neutral">&nbsp;</span> 778 - <span class="cline-any cline-neutral">&nbsp;</span> 779 - <span class="cline-any cline-yes">180x</span> 780 - <span class="cline-any cline-neutral">&nbsp;</span> 781 - <span class="cline-any cline-yes">180x</span> 782 - <span class="cline-any cline-neutral">&nbsp;</span> 783 - <span class="cline-any cline-yes">179x</span> 784 - <span class="cline-any cline-neutral">&nbsp;</span> 785 - <span class="cline-any cline-neutral">&nbsp;</span> 786 - <span class="cline-any cline-yes">179x</span> 787 - <span class="cline-any cline-neutral">&nbsp;</span> 788 - <span class="cline-any cline-yes">179x</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-yes">78x</span> 793 - <span class="cline-any cline-neutral">&nbsp;</span> 794 - <span class="cline-any cline-yes">78x</span> 795 - <span class="cline-any cline-neutral">&nbsp;</span> 796 - <span class="cline-any cline-yes">48x</span> 797 - <span class="cline-any cline-yes">30x</span> 798 - <span class="cline-any cline-neutral">&nbsp;</span> 799 - <span class="cline-any cline-yes">78x</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-neutral">&nbsp;</span> 803 - <span class="cline-any cline-yes">184x</span> 804 - <span class="cline-any cline-neutral">&nbsp;</span> 805 - <span class="cline-any cline-yes">184x</span> 806 - <span class="cline-any cline-neutral">&nbsp;</span> 807 - <span class="cline-any cline-yes">2x</span> 808 - <span class="cline-any cline-yes">182x</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-yes">3x</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-yes">3x</span> 816 - <span class="cline-any cline-yes">3x</span> 817 - <span class="cline-any cline-yes">12x</span> 818 - <span class="cline-any cline-yes">12x</span> 819 - <span class="cline-any cline-neutral">&nbsp;</span> 820 - <span class="cline-any cline-neutral">&nbsp;</span> 821 - <span class="cline-any cline-neutral">&nbsp;</span> 822 - <span class="cline-any cline-yes">3x</span> 823 - <span class="cline-any cline-yes">13x</span> 824 - <span class="cline-any cline-yes">13x</span> 825 - <span class="cline-any cline-yes">13x</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">11x</span> 834 - <span class="cline-any cline-neutral">&nbsp;</span> 835 - <span class="cline-any cline-neutral">&nbsp;</span> 836 - <span class="cline-any cline-neutral">&nbsp;</span> 837 - <span class="cline-any cline-neutral">&nbsp;</span> 838 - <span class="cline-any cline-yes">78x</span> 839 - <span class="cline-any cline-yes">88x</span> 840 - <span class="cline-any cline-yes">14x</span> 841 - <span class="cline-any cline-yes">14x</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-neutral">&nbsp;</span> 845 - <span class="cline-any cline-neutral">&nbsp;</span> 846 - <span class="cline-any cline-yes">78x</span> 847 - <span class="cline-any cline-yes">83x</span> 848 - <span class="cline-any cline-yes">83x</span> 849 - <span class="cline-any cline-yes">19x</span> 850 - <span class="cline-any cline-yes">19x</span> 851 - <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span> 856 - <span class="cline-any cline-yes">78x</span> 857 - <span class="cline-any cline-yes">19x</span> 858 - <span class="cline-any cline-yes">19x</span> 859 - <span class="cline-any cline-yes">19x</span> 860 - <span class="cline-any cline-yes">19x</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-neutral">&nbsp;</span> 864 - <span class="cline-any cline-neutral">&nbsp;</span> 865 - <span class="cline-any cline-yes">17x</span> 866 - <span class="cline-any cline-neutral">&nbsp;</span> 867 - <span class="cline-any cline-yes">59x</span> 868 - <span class="cline-any cline-yes">2x</span> 869 - <span class="cline-any cline-yes">57x</span> 870 - <span class="cline-any cline-neutral">&nbsp;</span> 871 - <span class="cline-any cline-neutral">&nbsp;</span> 872 - <span class="cline-any cline-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">1x</span> 876 - <span class="cline-any cline-neutral">&nbsp;</span> 877 - <span class="cline-any cline-yes">1x</span> 878 - <span class="cline-any cline-yes">1x</span> 879 - <span class="cline-any cline-neutral">&nbsp;</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">123x</span> 885 - <span class="cline-any cline-neutral">&nbsp;</span> 886 - <span class="cline-any cline-yes">123x</span> 887 - <span class="cline-any cline-yes">123x</span> 888 - <span class="cline-any cline-neutral">&nbsp;</span> 889 - <span class="cline-any cline-yes">123x</span> 890 - <span class="cline-any cline-yes">182x</span> 891 - <span class="cline-any cline-yes">182x</span> 892 - <span class="cline-any cline-neutral">&nbsp;</span> 893 - <span class="cline-any cline-yes">182x</span> 894 - <span class="cline-any cline-yes">165x</span> 895 - <span class="cline-any cline-neutral">&nbsp;</span> 896 - <span class="cline-any cline-yes">165x</span> 897 - <span class="cline-any cline-yes">91x</span> 898 - <span class="cline-any cline-yes">1x</span> 899 - <span class="cline-any cline-neutral">&nbsp;</span> 900 - <span class="cline-any cline-yes">90x</span> 901 - <span class="cline-any cline-neutral">&nbsp;</span> 902 - <span class="cline-any cline-yes">74x</span> 903 - <span class="cline-any cline-yes">17x</span> 904 - <span class="cline-any cline-yes">17x</span> 905 - <span class="cline-any cline-no">&nbsp;</span> 906 - <span class="cline-any cline-no">&nbsp;</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-neutral">&nbsp;</span> 910 - <span class="cline-any cline-neutral">&nbsp;</span> 911 - <span class="cline-any cline-yes">123x</span> 912 - <span class="cline-any cline-yes">113x</span> 913 - <span class="cline-any cline-yes">113x</span> 914 - <span class="cline-any cline-neutral">&nbsp;</span> 915 - <span class="cline-any cline-neutral">&nbsp;</span> 916 - <span class="cline-any cline-neutral">&nbsp;</span> 917 - <span class="cline-any cline-neutral">&nbsp;</span> 918 - <span class="cline-any cline-yes">90x</span> 919 - <span class="cline-any cline-neutral">&nbsp;</span> 920 - <span class="cline-any cline-yes">89x</span> 921 - <span class="cline-any cline-neutral">&nbsp;</span> 922 - <span class="cline-any cline-neutral">&nbsp;</span> 923 - <span class="cline-any cline-yes">89x</span> 924 - <span class="cline-any cline-neutral">&nbsp;</span> 925 - <span class="cline-any cline-yes">90x</span> 926 - <span class="cline-any cline-yes">90x</span> 927 - <span class="cline-any cline-neutral">&nbsp;</span> 928 - <span class="cline-any cline-neutral">&nbsp;</span> 929 - <span class="cline-any cline-yes">90x</span> 930 - <span class="cline-any cline-yes">121x</span> 931 - <span class="cline-any cline-yes">117x</span> 932 - <span class="cline-any cline-neutral">&nbsp;</span> 933 - <span class="cline-any cline-yes">117x</span> 934 - <span class="cline-any cline-yes">89x</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">117x</span> 938 - <span class="cline-any cline-yes">82x</span> 939 - <span class="cline-any cline-yes">54x</span> 940 - <span class="cline-any cline-yes">54x</span> 941 - <span class="cline-any cline-neutral">&nbsp;</span> 942 - <span class="cline-any cline-yes">28x</span> 943 - <span class="cline-any cline-neutral">&nbsp;</span> 944 - <span class="cline-any cline-yes">30x</span> 945 - <span class="cline-any cline-yes">1x</span> 946 - <span class="cline-any cline-yes">1x</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-neutral">&nbsp;</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-yes">66x</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-yes">34x</span> 956 - <span class="cline-any cline-yes">34x</span> 957 - <span class="cline-any cline-yes">34x</span> 958 - <span class="cline-any cline-neutral">&nbsp;</span> 959 - <span class="cline-any cline-no">&nbsp;</span> 960 - <span class="cline-any cline-no">&nbsp;</span> 961 - <span class="cline-any cline-no">&nbsp;</span> 962 - <span class="cline-any cline-no">&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-yes">34x</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-yes">126x</span> 971 - <span class="cline-any cline-neutral">&nbsp;</span> 972 - <span class="cline-any cline-yes">126x</span> 973 - <span class="cline-any cline-yes">44x</span> 974 - <span class="cline-any cline-yes">44x</span> 975 - <span class="cline-any cline-neutral">&nbsp;</span> 976 - <span class="cline-any cline-neutral">&nbsp;</span> 977 - <span class="cline-any cline-neutral">&nbsp;</span> 978 - <span class="cline-any cline-neutral">&nbsp;</span> 979 - <span class="cline-any cline-yes">30x</span> 980 - <span class="cline-any cline-yes">29x</span> 981 - <span class="cline-any cline-yes">29x</span> 982 - <span class="cline-any cline-yes">29x</span> 983 - <span class="cline-any cline-neutral">&nbsp;</span> 984 - <span class="cline-any cline-neutral">&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">89x</span> 988 - <span class="cline-any cline-neutral">&nbsp;</span> 989 - <span class="cline-any cline-yes">15x</span> 990 - <span class="cline-any cline-yes">15x</span> 991 - <span class="cline-any cline-neutral">&nbsp;</span> 992 - <span class="cline-any cline-yes">15x</span> 993 - <span class="cline-any cline-yes">5x</span> 994 - <span class="cline-any cline-neutral">&nbsp;</span> 995 - <span class="cline-any cline-yes">5x</span> 996 - <span class="cline-any cline-yes">5x</span> 997 - <span class="cline-any cline-neutral">&nbsp;</span> 998 - <span class="cline-any cline-yes">5x</span> 999 - <span class="cline-any cline-no">&nbsp;</span> 1000 - <span class="cline-any cline-neutral">&nbsp;</span> 1001 - <span class="cline-any cline-no">&nbsp;</span> 1002 - <span class="cline-any cline-no">&nbsp;</span> 1003 - <span class="cline-any cline-yes">5x</span> 1004 - <span class="cline-any cline-neutral">&nbsp;</span> 1005 - <span class="cline-any cline-neutral">&nbsp;</span> 1006 - <span class="cline-any cline-neutral">&nbsp;</span> 1007 - <span class="cline-any cline-neutral">&nbsp;</span> 1008 - <span class="cline-any cline-yes">15x</span> 1009 - <span class="cline-any cline-neutral">&nbsp;</span> 1010 - <span class="cline-any cline-neutral">&nbsp;</span> 1011 - <span class="cline-any cline-neutral">&nbsp;</span> 1012 - <span class="cline-any cline-yes">28x</span> 1013 - <span class="cline-any cline-yes">27x</span> 1014 - <span class="cline-any cline-yes">27x</span> 1015 - <span class="cline-any cline-neutral">&nbsp;</span> 1016 - <span class="cline-any cline-neutral">&nbsp;</span> 1017 - <span class="cline-any cline-neutral">&nbsp;</span> 1018 - <span class="cline-any cline-neutral">&nbsp;</span> 1019 - <span class="cline-any cline-yes">125x</span> 1020 - <span class="cline-any cline-yes">125x</span> 1021 - <span class="cline-any cline-yes">125x</span> 1022 - <span class="cline-any cline-neutral">&nbsp;</span> 1023 - <span class="cline-any cline-neutral">&nbsp;</span> 1024 - <span class="cline-any cline-neutral">&nbsp;</span> 1025 - <span class="cline-any cline-neutral">&nbsp;</span> 1026 - <span class="cline-any cline-neutral">&nbsp;</span> 1027 - <span class="cline-any cline-yes">12x</span> 1028 - <span class="cline-any cline-neutral">&nbsp;</span> 1029 - <span class="cline-any cline-neutral">&nbsp;</span> 1030 - <span class="cline-any cline-neutral">&nbsp;</span> 1031 - <span class="cline-any cline-yes">355x</span> 1032 - <span class="cline-any cline-yes">355x</span> 1033 - <span class="cline-any cline-neutral">&nbsp;</span> 1034 - <span class="cline-any cline-neutral">&nbsp;</span> 1035 - <span class="cline-any cline-neutral">&nbsp;</span> 1036 - <span class="cline-any cline-yes">95x</span> 1037 - <span class="cline-any cline-neutral">&nbsp;</span> 1038 - <span class="cline-any cline-neutral">&nbsp;</span> 1039 - <span class="cline-any cline-neutral">&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-yes">900x</span> 1043 - <span class="cline-any cline-neutral">&nbsp;</span> 1044 - <span class="cline-any cline-neutral">&nbsp;</span> 1045 - <span class="cline-any cline-neutral">&nbsp;</span> 1046 - <span class="cline-any cline-neutral">&nbsp;</span> 1047 - <span class="cline-any cline-neutral">&nbsp;</span> 1048 - <span class="cline-any cline-yes">8x</span> 1049 - <span class="cline-any cline-neutral">&nbsp;</span> 1050 - <span class="cline-any cline-neutral">&nbsp;</span> 1051 - <span class="cline-any cline-neutral">&nbsp;</span> 1052 - <span class="cline-any cline-neutral">&nbsp;</span> 1053 - <span class="cline-any cline-neutral">&nbsp;</span> 1054 - <span class="cline-any cline-yes">134x</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-neutral">&nbsp;</span> 1059 - <span class="cline-any cline-neutral">&nbsp;</span> 1060 - <span class="cline-any cline-yes">61x</span> 1061 - <span class="cline-any cline-neutral">&nbsp;</span> 1062 - <span class="cline-any cline-neutral">&nbsp;</span> 1063 - <span class="cline-any cline-neutral">&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-yes">72x</span> 1067 - <span class="cline-any cline-neutral">&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-neutral">&nbsp;</span> 1071 - <span class="cline-any cline-neutral">&nbsp;</span> 1072 - <span class="cline-any cline-yes">275x</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-yes">3x</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-neutral">&nbsp;</span> 1079 - <span class="cline-any cline-neutral">&nbsp;</span> 1080 - <span class="cline-any cline-yes">189x</span> 1081 - <span class="cline-any cline-neutral">&nbsp;</span> 1082 - <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">type IdSet = Set&lt;string&gt;; 1083 - type IdMap = WeakMap&lt;ReadonlyNode&lt;Node&gt;, IdSet&gt;; 1084 - type SensivityMap = WeakMap&lt;ReadonlyNode&lt;Node&gt;, number&gt;; 1085 - &nbsp; 1086 - // Maps to a type that can only read properties 1087 - type StrongReadonly&lt;T&gt; = { readonly [K in keyof T as T[K] extends Function ? never : K]: T[K] }; 1088 - &nbsp; 1089 - declare const brand: unique symbol; 1090 - type Branded&lt;T, B extends string&gt; = T &amp; { [brand]: B }; 1091 - &nbsp; 1092 - type NodeReferencePair&lt;N extends Node&gt; = Readonly&lt;[N, ReadonlyNode&lt;N&gt;]&gt;; 1093 - type MatchingElementReferencePair&lt;E extends Element&gt; = Branded&lt;NodeReferencePair&lt;E&gt;, "MatchingElementPair"&gt;; 1094 - &nbsp; 1095 - // Maps a Node to a type limited to read-only properties and methods for that Node 1096 - type ReadonlyNode&lt;N extends Node&gt; = 1097 - | N 1098 - | (StrongReadonly&lt;N&gt; &amp; { 1099 - readonly cloneNode: (deep: true) =&gt; Node; 1100 - readonly childNodes: ReadonlyNodeList&lt;ChildNode&gt;; 1101 - readonly querySelectorAll: (query: string) =&gt; ReadonlyNodeList&lt;Element&gt;; 1102 - readonly parentElement: ReadonlyNode&lt;Element&gt; | null; 1103 - readonly hasAttribute: (name: string) =&gt; boolean; 1104 - readonly hasAttributes: () =&gt; boolean; 1105 - readonly hasChildNodes: () =&gt; boolean; 1106 - readonly children: ReadonlyNodeList&lt;Element&gt;; 1107 - }); 1108 - &nbsp; 1109 - // Maps a node to a read-only node list of nodes of that type 1110 - type ReadonlyNodeList&lt;N extends Node&gt; = 1111 - | NodeListOf&lt;N&gt; 1112 - | { 1113 - [Symbol.iterator](): IterableIterator&lt;ReadonlyNode&lt;N&gt;&gt;; 1114 - readonly [index: number]: ReadonlyNode&lt;N&gt;; 1115 - readonly length: NodeListOf&lt;N&gt;["length"]; 1116 - }; 1117 - &nbsp; 1118 - interface Options { 1119 - ignoreActiveValue?: boolean; 1120 - preserveModifiedValues?: boolean; 1121 - beforeNodeMorphed?: (node: Node, referenceNode: Node) =&gt; boolean; 1122 - afterNodeMorphed?: (node: Node, referenceNode: Node) =&gt; void; 1123 - beforeNodeAdded?: (node: Node) =&gt; boolean; 1124 - afterNodeAdded?: (node: Node) =&gt; void; 1125 - beforeNodeRemoved?: (node: Node) =&gt; boolean; 1126 - afterNodeRemoved?: (node: Node) =&gt; void; 1127 - beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) =&gt; boolean; 1128 - afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) =&gt; void; 1129 - beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) =&gt; boolean; 1130 - afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) =&gt; void; 1131 - } 1132 - &nbsp; 1133 - export function morph(node: ChildNode, reference: ChildNode | string, options: Options = {}): void { 1134 - if (typeof reference === "string") reference = parseChildNodeFromString(reference); 1135 - new Morph(options).morph([node, reference]); 1136 - } 1137 - &nbsp; 1138 - export function morphInner(element: Element, reference: Element | string, options: Options = {}): void { 1139 - if (typeof reference === "string") reference = parseElementFromString(reference); 1140 - new Morph(options).morphInner([element, reference]); 1141 - } 1142 - &nbsp; 1143 - function parseElementFromString(string: string): Element { 1144 - const node = parseChildNodeFromString(string); 1145 - &nbsp; 1146 - <span class="missing-if-branch" title="if path not taken" >I</span>if (isElement(node)) <span class="cstat-no" title="statement not covered" >return node;</span> 1147 - else throw new Error("[Morphlex] The string was not a valid HTML element."); 1148 - } 1149 - &nbsp; 1150 - function parseChildNodeFromString(string: string): ChildNode { 1151 - const parser = new DOMParser(); 1152 - const doc = parser.parseFromString(string, "text/html"); 1153 - &nbsp; 1154 - if (doc.childNodes.length === 1) return doc.body.firstChild as ChildNode; 1155 - else <span class="cstat-no" title="statement not covered" ><span class="missing-if-branch" title="else path not taken" >E</span>throw new Error("[Morphlex] The string was not a valid HTML node.");</span> 1156 - } 1157 - &nbsp; 1158 - class Morph { 1159 - readonly #idMap: IdMap; 1160 - readonly #sensivityMap: SensivityMap; 1161 - &nbsp; 1162 - readonly #ignoreActiveValue: boolean; 1163 - readonly #preserveModifiedValues: boolean; 1164 - readonly #beforeNodeMorphed?: (node: Node, referenceNode: Node) =&gt; boolean; 1165 - readonly #afterNodeMorphed?: (node: Node, referenceNode: Node) =&gt; void; 1166 - readonly #beforeNodeAdded?: (node: Node) =&gt; boolean; 1167 - readonly #afterNodeAdded?: (node: Node) =&gt; void; 1168 - readonly #beforeNodeRemoved?: (node: Node) =&gt; boolean; 1169 - readonly #afterNodeRemoved?: (node: Node) =&gt; void; 1170 - readonly #beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) =&gt; boolean; 1171 - readonly #afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) =&gt; void; 1172 - readonly #beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) =&gt; boolean; 1173 - readonly #afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) =&gt; void; 1174 - &nbsp; 1175 - constructor(options: Options = {}) { 1176 - this.#idMap = new WeakMap(); 1177 - this.#sensivityMap = new WeakMap(); 1178 - &nbsp; 1179 - this.#ignoreActiveValue = options.ignoreActiveValue || false; 1180 - this.#preserveModifiedValues = options.preserveModifiedValues || false; 1181 - this.#beforeNodeMorphed = options.beforeNodeMorphed; 1182 - this.#afterNodeMorphed = options.afterNodeMorphed; 1183 - this.#beforeNodeAdded = options.beforeNodeAdded; 1184 - this.#afterNodeAdded = options.afterNodeAdded; 1185 - this.#beforeNodeRemoved = options.beforeNodeRemoved; 1186 - this.#afterNodeRemoved = options.afterNodeRemoved; 1187 - this.#beforeAttributeUpdated = options.beforeAttributeUpdated; 1188 - this.#afterAttributeUpdated = options.afterAttributeUpdated; 1189 - this.#beforePropertyUpdated = options.beforePropertyUpdated; 1190 - this.#afterPropertyUpdated = options.afterPropertyUpdated; 1191 - } 1192 - &nbsp; 1193 - morph(pair: NodeReferencePair&lt;ChildNode&gt;): void { 1194 - this.#withAriaBusy(pair[0], () =&gt; { 1195 - if (isParentNodePair(pair)) this.#buildMaps(pair); 1196 - this.#morphNode(pair); 1197 - }); 1198 - } 1199 - &nbsp; 1200 - morphInner(pair: NodeReferencePair&lt;Element&gt;): void { 1201 - this.#withAriaBusy(pair[0], () =&gt; { 1202 - if (isMatchingElementPair(pair)) { 1203 - this.#buildMaps(pair); 1204 - this.#morphMatchingElementContent(pair); 1205 - } else { 1206 - throw new Error("[Morphlex] You can only do an inner morph with matching elements."); 1207 - } 1208 - }); 1209 - } 1210 - &nbsp; 1211 - #withAriaBusy(node: Node, block: () =&gt; void): void { 1212 - if (isElement(node)) { 1213 - const originalAriaBusy = node.ariaBusy; 1214 - node.ariaBusy = "true"; 1215 - block(); 1216 - node.ariaBusy = originalAriaBusy; 1217 - } else block(); 1218 - } 1219 - &nbsp; 1220 - #buildMaps([node, reference]: NodeReferencePair&lt;ParentNode&gt;): void { 1221 - this.#mapIdSets(node); 1222 - this.#mapIdSets(reference); 1223 - this.#mapSensivity(node); 1224 - } 1225 - &nbsp; 1226 - #mapSensivity(node: ReadonlyNode&lt;ParentNode&gt;): void { 1227 - const sensitiveElements = node.querySelectorAll("audio,canvas,embed,iframe,input,object,textarea,video"); 1228 - &nbsp; 1229 - const sensitiveElementsLength = sensitiveElements.length; 1230 - for (let i = 0; i &lt; sensitiveElementsLength; i++) { 1231 - const sensitiveElement = sensitiveElements[i]; 1232 - let sensivity = 0; 1233 - &nbsp; 1234 - if (isInput(sensitiveElement) || isTextArea(sensitiveElement)) { 1235 - sensivity++; 1236 - &nbsp; 1237 - if (sensitiveElement.value !== sensitiveElement.defaultValue) sensivity++; 1238 - if (sensitiveElement === document.activeElement) sensivity++; 1239 - } else { 1240 - sensivity += 3; 1241 - &nbsp; 1242 - if (isMedia(sensitiveElement) &amp;&amp; !sensitiveElement.ended) { 1243 - if (!sensitiveElement.paused) sensivity++; 1244 - if (sensitiveElement.currentTime &gt; 0) sensivity++; 1245 - } 1246 - } 1247 - &nbsp; 1248 - let current: ReadonlyNode&lt;Element&gt; | null = sensitiveElement; 1249 - while (current) { 1250 - this.#sensivityMap.set(current, (this.#sensivityMap.get(current) || 0) + sensivity); 1251 - if (current === node) break; 1252 - current = current.parentElement; 1253 - } 1254 - } 1255 - } 1256 - &nbsp; 1257 - // For each node with an ID, push that ID into the IdSet on the IdMap, for each of its parent elements. 1258 - #mapIdSets(node: ReadonlyNode&lt;ParentNode&gt;): void { 1259 - const elementsWithIds = node.querySelectorAll("[id]"); 1260 - &nbsp; 1261 - const elementsWithIdsLength = elementsWithIds.length; 1262 - for (let i = 0; i &lt; elementsWithIdsLength; i++) { 1263 - const elementWithId = elementsWithIds[i]; 1264 - const id = elementWithId.id; 1265 - &nbsp; 1266 - // Ignore empty IDs 1267 - if (id === "") continue; 1268 - &nbsp; 1269 - let current: ReadonlyNode&lt;Element&gt; | null = elementWithId; 1270 - &nbsp; 1271 - while (current) { 1272 - const idSet: IdSet | undefined = this.#idMap.get(current); 1273 - idSet ? idSet.add(id) : this.#idMap.set(current, new Set([id])); 1274 - if (current === node) break; 1275 - current = current.parentElement; 1276 - } 1277 - } 1278 - } 1279 - &nbsp; 1280 - // This is where we actually morph the nodes. The `morph` function (above) exists only to set up the `idMap`. 1281 - #morphNode(pair: NodeReferencePair&lt;ChildNode&gt;): void { 1282 - if (isMatchingElementPair(pair)) this.#morphMatchingElementNode(pair); 1283 - else this.#morphOtherNode(pair); 1284 - } 1285 - &nbsp; 1286 - #morphMatchingElementNode(pair: MatchingElementReferencePair&lt;Element&gt;): void { 1287 - const [node, reference] = pair; 1288 - &nbsp; 1289 - if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) return; 1290 - &nbsp; 1291 - if (node.hasAttributes() || reference.hasAttributes()) this.#morphAttributes(pair); 1292 - &nbsp; 1293 - // TODO: Should use a branded pair here. 1294 - this.#morphMatchingElementContent(pair); 1295 - &nbsp; 1296 - this.#afterNodeMorphed?.(node, writableNode(reference)); 1297 - } 1298 - &nbsp; 1299 - #morphOtherNode([node, reference]: NodeReferencePair&lt;ChildNode&gt;): void { 1300 - <span class="missing-if-branch" title="if path not taken" >I</span>if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) <span class="cstat-no" title="statement not covered" >return;</span> 1301 - &nbsp; 1302 - if (node.nodeType === reference.nodeType &amp;&amp; node.nodeValue !== null &amp;&amp; reference.nodeValue !== null) { 1303 - // Handle text nodes, comments, and CDATA sections. 1304 - this.#updateProperty(node, "nodeValue", reference.nodeValue); 1305 - } else this.#replaceNode(node, reference.cloneNode(true)); 1306 - &nbsp; 1307 - this.#afterNodeMorphed?.(node, writableNode(reference)); 1308 - } 1309 - &nbsp; 1310 - #morphMatchingElementContent(pair: MatchingElementReferencePair&lt;Element&gt;): void { 1311 - const [node, reference] = pair; 1312 - &nbsp; 1313 - if (isHead(node)) { 1314 - // We can pass the reference as a head here becuase we know it's the same as the node. 1315 - this.#morphHeadContents(pair as MatchingElementReferencePair&lt;HTMLHeadElement&gt;); 1316 - } else if (node.hasChildNodes() || reference.hasChildNodes()) this.#morphChildNodes(pair); 1317 - } 1318 - &nbsp; 1319 - #morphHeadContents([node, reference]: MatchingElementReferencePair&lt;HTMLHeadElement&gt;): void { 1320 - const refChildNodesMap: Map&lt;string, ReadonlyNode&lt;Element&gt;&gt; = new Map(); 1321 - &nbsp; 1322 - // Generate a map of the reference head element’s child nodes, keyed by their outerHTML. 1323 - const referenceChildrenLength = reference.children.length; 1324 - for (let i = 0; i &lt; referenceChildrenLength; i++) { 1325 - const child = reference.children[i]; 1326 - refChildNodesMap.set(child.outerHTML, child); 1327 - } 1328 - &nbsp; 1329 - // Iterate backwards to safely remove children without affecting indices 1330 - for (let i = node.children.length - 1; i &gt;= 0; i--) { 1331 - const child = node.children[i]; 1332 - const key = child.outerHTML; 1333 - const refChild = refChildNodesMap.get(key); 1334 - &nbsp; 1335 - // If the child is in the reference map already, we don't need to add it later. 1336 - // If it's not in the map, we need to remove it from the node. 1337 - refChild ? refChildNodesMap.delete(key) : this.#removeNode(child); 1338 - } 1339 - &nbsp; 1340 - // Any remaining nodes in the map should be appended to the head. 1341 - for (const refChild of refChildNodesMap.values()) this.#appendChild(node, refChild.cloneNode(true)); 1342 - } 1343 - &nbsp; 1344 - #morphAttributes([element, reference]: MatchingElementReferencePair&lt;Element&gt;): void { 1345 - // Remove any excess attributes from the element that aren’t present in the reference. 1346 - for (const { name, value } of element.attributes) { 1347 - if (!reference.hasAttribute(name) &amp;&amp; (this.#beforeAttributeUpdated?.(element, name, null) ?? true)) { 1348 - element.removeAttribute(name); 1349 - this.#afterAttributeUpdated?.(element, name, value); 1350 - } 1351 - } 1352 - &nbsp; 1353 - // Copy attributes from the reference to the element, if they don’t already match. 1354 - for (const { name, value } of reference.attributes) { 1355 - const previousValue = element.getAttribute(name); 1356 - if (previousValue !== value &amp;&amp; (this.#beforeAttributeUpdated?.(element, name, value) ?? true)) { 1357 - element.setAttribute(name, value); 1358 - this.#afterAttributeUpdated?.(element, name, previousValue); 1359 - } 1360 - } 1361 - &nbsp; 1362 - // For certain types of elements, we need to do some extra work to ensure 1363 - // the element’s state matches the reference elements’ state. 1364 - if (isInput(element) &amp;&amp; isInput(reference)) { 1365 - this.#updateProperty(element, "checked", reference.checked); 1366 - this.#updateProperty(element, "disabled", reference.disabled); 1367 - this.#updateProperty(element, "indeterminate", reference.indeterminate); 1368 - if ( 1369 - element.type !== "file" &amp;&amp; 1370 - !(this.#ignoreActiveValue &amp;&amp; document.activeElement === element) &amp;&amp; 1371 - !(this.#preserveModifiedValues &amp;&amp; <span class="branch-1 cbranch-no" title="branch not covered" >element.name === reference.name &amp;&amp; <span class="branch-2 cbranch-no" title="branch not covered" >e</span>lement.value !== element.defaultValue)</span> 1372 - ) { 1373 - this.#updateProperty(element, "value", reference.value); 1374 - } 1375 - } else if (isOption(element) &amp;&amp; isOption(reference)) { 1376 - this.#updateProperty(element, "selected", reference.selected); 1377 - } else if ( 1378 - isTextArea(element) &amp;&amp; 1379 - isTextArea(reference) &amp;&amp; 1380 - !(this.#ignoreActiveValue &amp;&amp; document.activeElement === element) &amp;&amp; 1381 - !(this.#preserveModifiedValues &amp;&amp; element.name === reference.name &amp;&amp; element.value !== element.defaultValue) 1382 - ) { 1383 - this.#updateProperty(element, "value", reference.value); 1384 - &nbsp; 1385 - const text = element.firstElementChild; 1386 - <span class="missing-if-branch" title="else path not taken" >E</span>if (text) this.#updateProperty(text, "textContent", reference.value); 1387 - } 1388 - } 1389 - &nbsp; 1390 - // Iterates over the child nodes of the reference element, morphing the main element’s child nodes to match. 1391 - #morphChildNodes(pair: MatchingElementReferencePair&lt;Element&gt;): void { 1392 - const [element, reference] = pair; 1393 - &nbsp; 1394 - const childNodes = element.childNodes; 1395 - const refChildNodes = reference.childNodes; 1396 - &nbsp; 1397 - for (let i = 0; i &lt; refChildNodes.length; i++) { 1398 - const child = childNodes[i] as ChildNode | null; 1399 - const refChild = refChildNodes[i] as ReadonlyNode&lt;ChildNode&gt; | null; 1400 - &nbsp; 1401 - if (child &amp;&amp; refChild) { 1402 - const pair: NodeReferencePair&lt;ChildNode&gt; = [child, refChild]; 1403 - &nbsp; 1404 - if (isMatchingElementPair(pair)) { 1405 - if (isHead(pair[0])) { 1406 - this.#morphHeadContents(pair as MatchingElementReferencePair&lt;HTMLHeadElement&gt;); 1407 - } else { 1408 - this.#morphChildElement(pair, element); 1409 - } 1410 - } else this.#morphOtherNode(pair); 1411 - } else if (refChild) { 1412 - this.#appendChild(element, refChild.cloneNode(true)); 1413 - <span class="cstat-no" title="statement not covered" > <span class="missing-if-branch" title="else path not taken" >E</span>} else if (child) {</span> 1414 - <span class="cstat-no" title="statement not covered" > this.#removeNode(child);</span> 1415 - } 1416 - } 1417 - &nbsp; 1418 - // Clean up any excess nodes that may be left over 1419 - while (childNodes.length &gt; refChildNodes.length) { 1420 - const child = element.lastChild; 1421 - <span class="missing-if-branch" title="else path not taken" >E</span>if (child) this.#removeNode(child); 1422 - } 1423 - } 1424 - &nbsp; 1425 - #morphChildElement([child, reference]: MatchingElementReferencePair&lt;Element&gt;, parent: Element): void { 1426 - if (!(this.#beforeNodeMorphed?.(child, writableNode(reference)) ?? true)) return; 1427 - &nbsp; 1428 - const refIdSet = this.#idMap.get(reference); 1429 - &nbsp; 1430 - // Generate the array in advance of the loop 1431 - const refSetArray = refIdSet ? [...refIdSet] : []; 1432 - &nbsp; 1433 - let currentNode: ChildNode | null = child; 1434 - let nextMatchByTagName: ChildNode | null = null; 1435 - &nbsp; 1436 - // Try find a match by idSet, while also looking out for the next best match by tagName. 1437 - while (currentNode) { 1438 - if (isElement(currentNode)) { 1439 - const id = currentNode.id; 1440 - &nbsp; 1441 - if (!nextMatchByTagName &amp;&amp; currentNode.localName === reference.localName) { 1442 - nextMatchByTagName = currentNode; 1443 - } 1444 - &nbsp; 1445 - if (id !== "") { 1446 - if (id === reference.id) { 1447 - this.#insertBefore(parent, currentNode, child); 1448 - return this.#morphNode([currentNode, reference]); 1449 - } else { 1450 - const currentIdSet = this.#idMap.get(currentNode); 1451 - &nbsp; 1452 - if (currentIdSet &amp;&amp; refSetArray.some((it) =&gt; currentIdSet.has(it))) { 1453 - this.#insertBefore(parent, currentNode, child); 1454 - return this.#morphNode([currentNode, reference]); 1455 - } 1456 - } 1457 - } 1458 - } 1459 - &nbsp; 1460 - currentNode = currentNode.nextSibling; 1461 - } 1462 - &nbsp; 1463 - if (nextMatchByTagName) { 1464 - this.#insertBefore(parent, nextMatchByTagName, child); 1465 - this.#morphNode([nextMatchByTagName, reference]); 1466 - } else <span class="missing-if-branch" title="else path not taken" >E</span>{ 1467 - const newNode = <span class="cstat-no" title="statement not covered" >reference.cloneNode(true);</span> 1468 - <span class="cstat-no" title="statement not covered" > if (this.#beforeNodeAdded?.(newNode) ?? true) {</span> 1469 - <span class="cstat-no" title="statement not covered" > this.#insertBefore(parent, newNode, child);</span> 1470 - <span class="cstat-no" title="statement not covered" > this.#afterNodeAdded?.(newNode);</span> 1471 - } 1472 - } 1473 - &nbsp; 1474 - this.#afterNodeMorphed?.(child, writableNode(reference)); 1475 - } 1476 - &nbsp; 1477 - #updateProperty&lt;N extends Node, P extends keyof N&gt;(node: N, propertyName: P, newValue: N[P]): void { 1478 - const previousValue = node[propertyName]; 1479 - &nbsp; 1480 - if (previousValue !== newValue &amp;&amp; (this.#beforePropertyUpdated?.(node, propertyName, newValue) ?? true)) { 1481 - node[propertyName] = newValue; 1482 - this.#afterPropertyUpdated?.(node, propertyName, previousValue); 1483 - } 1484 - } 1485 - &nbsp; 1486 - #replaceNode(node: ChildNode, newNode: Node): void { 1487 - if ((this.#beforeNodeRemoved?.(node) ?? true) &amp;&amp; (this.#beforeNodeAdded?.(newNode) ?? true)) { 1488 - node.replaceWith(newNode); 1489 - this.#afterNodeAdded?.(newNode); 1490 - this.#afterNodeRemoved?.(node); 1491 - } 1492 - } 1493 - &nbsp; 1494 - #insertBefore(parent: ParentNode, node: Node, insertionPoint: ChildNode): void { 1495 - if (node === insertionPoint) return; 1496 - &nbsp; 1497 - <span class="missing-if-branch" title="else path not taken" >E</span>if (isElement(node)) { 1498 - const sensitivity = this.#sensivityMap.get(node) ?? 0; 1499 - &nbsp; 1500 - if (sensitivity &gt; 0) { 1501 - let previousNode = node.previousSibling; 1502 - &nbsp; 1503 - while (previousNode) { 1504 - const previousNodeSensitivity = this.#sensivityMap.get(previousNode) ?? <span class="branch-1 cbranch-no" title="branch not covered" >0;</span> 1505 - &nbsp; 1506 - <span class="missing-if-branch" title="if path not taken" >I</span>if (previousNodeSensitivity &lt; sensitivity) { 1507 - <span class="cstat-no" title="statement not covered" > parent.insertBefore(previousNode, node.nextSibling);</span> 1508 - &nbsp; 1509 - <span class="cstat-no" title="statement not covered" > if (previousNode === insertionPoint) <span class="cstat-no" title="statement not covered" >return;</span></span> 1510 - <span class="cstat-no" title="statement not covered" > previousNode = node.previousSibling;</span> 1511 - } else break; 1512 - } 1513 - } 1514 - } 1515 - &nbsp; 1516 - parent.insertBefore(node, insertionPoint); 1517 - } 1518 - &nbsp; 1519 - #appendChild(node: ParentNode, newNode: Node): void { 1520 - if (this.#beforeNodeAdded?.(newNode) ?? true) { 1521 - node.appendChild(newNode); 1522 - this.#afterNodeAdded?.(newNode); 1523 - } 1524 - } 1525 - &nbsp; 1526 - #removeNode(node: ChildNode): void { 1527 - <span class="missing-if-branch" title="else path not taken" >E</span>if (this.#beforeNodeRemoved?.(node) ?? true) { 1528 - node.remove(); 1529 - this.#afterNodeRemoved?.(node); 1530 - } 1531 - } 1532 - } 1533 - &nbsp; 1534 - function writableNode&lt;N extends Node&gt;(node: ReadonlyNode&lt;N&gt;): N { 1535 - return node as N; 1536 - } 1537 - &nbsp; 1538 - function isMatchingElementPair(pair: NodeReferencePair&lt;Node&gt;): pair is MatchingElementReferencePair&lt;Element&gt; { 1539 - const [a, b] = pair; 1540 - return isElement(a) &amp;&amp; isElement(b) &amp;&amp; a.localName === b.localName; 1541 - } 1542 - &nbsp; 1543 - function isParentNodePair(pair: NodeReferencePair&lt;Node&gt;): pair is NodeReferencePair&lt;ParentNode&gt; { 1544 - return isParentNode(pair[0]) &amp;&amp; isParentNode(pair[1]); 1545 - } 1546 - &nbsp; 1547 - function isElement(node: Node): node is Element; 1548 - function isElement(node: ReadonlyNode&lt;Node&gt;): node is ReadonlyNode&lt;Element&gt;; 1549 - function isElement(node: Node | ReadonlyNode&lt;Node&gt;): boolean { 1550 - return node.nodeType === 1; 1551 - } 1552 - &nbsp; 1553 - function isMedia(element: Element): element is HTMLMediaElement; 1554 - function isMedia(element: ReadonlyNode&lt;Element&gt;): element is ReadonlyNode&lt;HTMLMediaElement&gt;; 1555 - function isMedia(element: Element | ReadonlyNode&lt;Element&gt;): boolean { 1556 - return element.localName === "video" || element.localName === "audio"; 1557 - } 1558 - &nbsp; 1559 - function isInput(element: Element): element is HTMLInputElement; 1560 - function isInput(element: ReadonlyNode&lt;Element&gt;): element is ReadonlyNode&lt;HTMLInputElement&gt;; 1561 - function isInput(element: Element | ReadonlyNode&lt;Element&gt;): boolean { 1562 - return element.localName === "input"; 1563 - } 1564 - &nbsp; 1565 - function isOption(element: Element): element is HTMLOptionElement; 1566 - function isOption(element: ReadonlyNode&lt;Element&gt;): element is ReadonlyNode&lt;HTMLOptionElement&gt;; 1567 - function isOption(element: Element | ReadonlyNode&lt;Element&gt;): boolean { 1568 - return element.localName === "option"; 1569 - } 1570 - &nbsp; 1571 - function isTextArea(element: Element): element is HTMLTextAreaElement; 1572 - function isTextArea(element: ReadonlyNode&lt;Element&gt;): element is ReadonlyNode&lt;HTMLTextAreaElement&gt;; 1573 - function isTextArea(element: Element | ReadonlyNode&lt;Element&gt;): boolean { 1574 - return element.localName === "textarea"; 1575 - } 1576 - &nbsp; 1577 - function isHead(element: Element): element is HTMLHeadElement; 1578 - function isHead(element: ReadonlyNode&lt;Element&gt;): element is ReadonlyNode&lt;HTMLHeadElement&gt;; 1579 - function isHead(element: Element | ReadonlyNode&lt;Element&gt;): boolean { 1580 - return element.localName === "head"; 1581 - } 1582 - &nbsp; 1583 - const parentNodeTypes = new Set([1, 9, 11]); 1584 - &nbsp; 1585 - function isParentNode(node: Node): node is ParentNode; 1586 - function isParentNode(node: ReadonlyNode&lt;Node&gt;): node is ReadonlyNode&lt;ParentNode&gt;; 1587 - function isParentNode(node: Node | ReadonlyNode&lt;Node&gt;): boolean { 1588 - return parentNodeTypes.has(node.nodeType); 1589 - } 1590 - &nbsp;</pre></td></tr></table></pre> 1591 - 1592 - <div class='push'></div><!-- for sticky footer --> 1593 - </div><!-- /wrapper --> 1594 - <div class='footer quiet pad2 space-top1 center small'> 1595 - Code coverage generated by 1596 - <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> 1597 - at 2025-10-30T21:26:27.959Z 1598 - </div> 1599 - <script src="prettify.js"></script> 1600 - <script> 1601 - window.onload = function () { 1602 - prettyPrint(); 1603 - }; 1604 - </script> 1605 - <script src="sorter.js"></script> 1606 - <script src="block-navigation.js"></script> 1607 - </body> 1608 - </html> 1609 -
-1
coverage/prettify.css
··· 1 - .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
-2
coverage/prettify.js
··· 1 - /* eslint-disable */ 2 - window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.ignoreCase){ac=true}else{if(/[a-z]/i.test(ae.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){S=true;ac=false;break}}}var Y={b:8,t:9,n:10,v:11,f:12,r:13};function ab(ah){var ag=ah.charCodeAt(0);if(ag!==92){return ag}var af=ah.charAt(1);ag=Y[af];if(ag){return ag}else{if("0"<=af&&af<="7"){return parseInt(ah.substring(1),8)}else{if(af==="u"||af==="x"){return parseInt(ah.substring(2),16)}else{return ah.charCodeAt(1)}}}}function T(af){if(af<32){return(af<16?"\\x0":"\\x")+af.toString(16)}var ag=String.fromCharCode(af);if(ag==="\\"||ag==="-"||ag==="["||ag==="]"){ag="\\"+ag}return ag}function X(am){var aq=am.substring(1,am.length-1).match(new RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));var ak=[];var af=[];var ao=aq[0]==="^";for(var ar=ao?1:0,aj=aq.length;ar<aj;++ar){var ah=aq[ar];if(/\\[bdsw]/i.test(ah)){ak.push(ah)}else{var ag=ab(ah);var al;if(ar+2<aj&&"-"===aq[ar+1]){al=ab(aq[ar+2]);ar+=2}else{al=ag}af.push([ag,al]);if(!(al<65||ag>122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;ar<af.length;++ar){var at=af[ar];if(at[0]<=ap[1]+1){ap[1]=Math.max(ap[1],at[1])}else{ai.push(ap=at)}}var an=["["];if(ao){an.push("^")}an.push.apply(an,ak);for(var ar=0;ar<ai.length;++ar){var at=ai[ar];an.push(T(at[0]));if(at[1]>at[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){an[af]=-1}}}}for(var ak=1;ak<an.length;++ak){if(-1===an[ak]){an[ak]=++ad}}for(var ak=0,am=0;ak<ah;++ak){var ag=aj[ak];if(ag==="("){++am;if(an[am]===undefined){aj[ak]="(?:"}}else{if("\\"===ag.charAt(0)){var af=+ag.substring(1);if(af&&af<=am){aj[ak]="\\"+an[am]}}}}for(var ak=0,am=0;ak<ah;++ak){if("^"===aj[ak]&&"^"!==aj[ak+1]){aj[ak]=""}}if(al.ignoreCase&&S){for(var ak=0;ak<ah;++ak){var ag=aj[ak];var ai=ag.charAt(0);if(ag.length>=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V<U;++V){var ae=Z[V];if(ae.global||ae.multiline){throw new Error(""+ae)}aa.push("(?:"+W(ae)+")")}return new RegExp(aa.join("|"),ac?"gi":"g")}function a(V){var U=/(?:^|\s)nocode(?:\s|$)/;var X=[];var T=0;var Z=[];var W=0;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=document.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Y=S&&"pre"===S.substring(0,3);function aa(ab){switch(ab.nodeType){case 1:if(U.test(ab.className)){return}for(var ae=ab.firstChild;ae;ae=ae.nextSibling){aa(ae)}var ad=ab.nodeName;if("BR"===ad||"LI"===ad){X[W]="\n";Z[W<<1]=T++;Z[(W++<<1)|1]=ab}break;case 3:case 4:var ac=ab.nodeValue;if(ac.length){if(!Y){ac=ac.replace(/[ \t\r\n]+/g," ")}else{ac=ac.replace(/\r\n?/g,"\n")}X[W]=ac;Z[W<<1]=T;T+=ac.length;Z[(W++<<1)|1]=ab}break}}aa(V);return{sourceCode:X.join("").replace(/\n$/,""),spans:Z}}function B(S,U,W,T){if(!U){return}var V={sourceCode:U,basePos:S};W(V);T.push.apply(T,V.decorations)}var v=/\S/;function o(S){var V=undefined;for(var U=S.firstChild;U;U=U.nextSibling){var T=U.nodeType;V=(T===1)?(V?S:U):(T===3)?(v.test(U.nodeValue)?S:V):V}return V===S?undefined:V}function g(U,T){var S={};var V;(function(){var ad=U.concat(T);var ah=[];var ag={};for(var ab=0,Z=ad.length;ab<Z;++ab){var Y=ad[ab];var ac=Y[3];if(ac){for(var ae=ac.length;--ae>=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae<aq;++ae){var ag=an[ae];var ap=aj[ag];var ai=void 0;var am;if(typeof ap==="string"){am=false}else{var aa=S[ag.charAt(0)];if(aa){ai=ag.match(aa[1]);ap=aa[0]}else{for(var ao=0;ao<X;++ao){aa=T[ao];ai=ag.match(aa[1]);if(ai){ap=aa[0];break}}if(!ai){ap=F}}am=ap.length>=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y<W.length;++Y){ae(W[Y])}if(ag===(ag|0)){W[0].setAttribute("value",ag)}var aa=ac.createElement("OL");aa.className="linenums";var X=Math.max(0,((ag-1))|0)||0;for(var Y=0,T=W.length;Y<T;++Y){af=W[Y];af.className="L"+((Y+X)%10);if(!af.firstChild){af.appendChild(ac.createTextNode("\xA0"))}aa.appendChild(af)}V.appendChild(aa)}function D(ac){var aj=/\bMSIE\b/.test(navigator.userAgent);var am=/\n/g;var al=ac.sourceCode;var an=al.length;var V=0;var aa=ac.spans;var T=aa.length;var ah=0;var X=ac.decorations;var Y=X.length;var Z=0;X[Y]=an;var ar,aq;for(aq=ar=0;aq<Y;){if(X[aq]!==X[aq+2]){X[ar++]=X[aq++];X[ar++]=X[aq++]}else{aq+=2}}Y=ar;for(aq=ar=0;aq<Y;){var at=X[aq];var ab=X[aq+1];var W=aq+2;while(W+2<=Y&&X[W+1]===ab){W+=2}X[ar++]=at;X[ar++]=ab;aq=W}Y=X.length=ar;var ae=null;while(ah<T){var af=aa[ah];var S=aa[ah+2]||an;var ag=X[Z];var ap=X[Z+2]||an;var W=Math.min(S,ap);var ak=aa[ah+1];var U;if(ak.nodeType!==1&&(U=al.substring(V,W))){if(aj){U=U.replace(am,"\r")}ak.nodeValue=U;var ai=ak.ownerDocument;var ao=ai.createElement("SPAN");ao.className=X[Z+1];var ad=ak.parentNode;ad.replaceChild(ao,ak);ao.appendChild(ak);if(V<S){aa[ah+1]=ak=ai.createTextNode(al.substring(W,S));ad.insertBefore(ak,ao.nextSibling)}}V=W;if(V>=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*</.test(S)?"default-markup":"default-code"}return t[T]}c(K,["default-code"]);c(g([],[[F,/^[^<?]+/],[E,/^<!\w[^>]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa<ac.length;++aa){for(var Z=0,V=ac[aa].length;Z<V;++Z){T.push(ac[aa][Z])}}ac=null;var W=Date;if(!W.now){W={now:function(){return +(new Date)}}}var X=0;var S;var ab=/\blang(?:uage)?-([\w.]+)(?!\S)/;var ae=/\bprettyprint\b/;function U(){var ag=(window.PR_SHOULD_USE_CONTINUATION?W.now()+250:Infinity);for(;X<T.length&&W.now()<ag;X++){var aj=T[X];var ai=aj.className;if(ai.indexOf("prettyprint")>=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X<T.length){setTimeout(U,250)}else{if(ad){ad()}}}U()}window.prettyPrintOne=y;window.prettyPrint=b;window.PR={createSimpleLexer:g,registerLangHandler:c,sourceDecorator:i,PR_ATTRIB_NAME:P,PR_ATTRIB_VALUE:n,PR_COMMENT:j,PR_DECLARATION:E,PR_KEYWORD:z,PR_LITERAL:G,PR_NOCODE:N,PR_PLAIN:F,PR_PUNCTUATION:L,PR_SOURCE:J,PR_STRING:C,PR_TAG:m,PR_TYPE:O}})();PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_DECLARATION,/^<!\w[^>]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^<script\b[^>]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:<!--|-->)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]);
coverage/sort-arrow-sprite.png

This is a binary file and will not be displayed.

-210
coverage/sorter.js
··· 1 - /* eslint-disable */ 2 - var addSorting = (function() { 3 - 'use strict'; 4 - var cols, 5 - currentSort = { 6 - index: 0, 7 - desc: false 8 - }; 9 - 10 - // returns the summary table element 11 - function getTable() { 12 - return document.querySelector('.coverage-summary'); 13 - } 14 - // returns the thead element of the summary table 15 - function getTableHeader() { 16 - return getTable().querySelector('thead tr'); 17 - } 18 - // returns the tbody element of the summary table 19 - function getTableBody() { 20 - return getTable().querySelector('tbody'); 21 - } 22 - // returns the th element for nth column 23 - function getNthColumn(n) { 24 - return getTableHeader().querySelectorAll('th')[n]; 25 - } 26 - 27 - function onFilterInput() { 28 - const searchValue = document.getElementById('fileSearch').value; 29 - const rows = document.getElementsByTagName('tbody')[0].children; 30 - 31 - // Try to create a RegExp from the searchValue. If it fails (invalid regex), 32 - // it will be treated as a plain text search 33 - let searchRegex; 34 - try { 35 - searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive 36 - } catch (error) { 37 - searchRegex = null; 38 - } 39 - 40 - for (let i = 0; i < rows.length; i++) { 41 - const row = rows[i]; 42 - let isMatch = false; 43 - 44 - if (searchRegex) { 45 - // If a valid regex was created, use it for matching 46 - isMatch = searchRegex.test(row.textContent); 47 - } else { 48 - // Otherwise, fall back to the original plain text search 49 - isMatch = row.textContent 50 - .toLowerCase() 51 - .includes(searchValue.toLowerCase()); 52 - } 53 - 54 - row.style.display = isMatch ? '' : 'none'; 55 - } 56 - } 57 - 58 - // loads the search box 59 - function addSearchBox() { 60 - var template = document.getElementById('filterTemplate'); 61 - var templateClone = template.content.cloneNode(true); 62 - templateClone.getElementById('fileSearch').oninput = onFilterInput; 63 - template.parentElement.appendChild(templateClone); 64 - } 65 - 66 - // loads all columns 67 - function loadColumns() { 68 - var colNodes = getTableHeader().querySelectorAll('th'), 69 - colNode, 70 - cols = [], 71 - col, 72 - i; 73 - 74 - for (i = 0; i < colNodes.length; i += 1) { 75 - colNode = colNodes[i]; 76 - col = { 77 - key: colNode.getAttribute('data-col'), 78 - sortable: !colNode.getAttribute('data-nosort'), 79 - type: colNode.getAttribute('data-type') || 'string' 80 - }; 81 - cols.push(col); 82 - if (col.sortable) { 83 - col.defaultDescSort = col.type === 'number'; 84 - colNode.innerHTML = 85 - colNode.innerHTML + '<span class="sorter"></span>'; 86 - } 87 - } 88 - return cols; 89 - } 90 - // attaches a data attribute to every tr element with an object 91 - // of data values keyed by column name 92 - function loadRowData(tableRow) { 93 - var tableCols = tableRow.querySelectorAll('td'), 94 - colNode, 95 - col, 96 - data = {}, 97 - i, 98 - val; 99 - for (i = 0; i < tableCols.length; i += 1) { 100 - colNode = tableCols[i]; 101 - col = cols[i]; 102 - val = colNode.getAttribute('data-value'); 103 - if (col.type === 'number') { 104 - val = Number(val); 105 - } 106 - data[col.key] = val; 107 - } 108 - return data; 109 - } 110 - // loads all row data 111 - function loadData() { 112 - var rows = getTableBody().querySelectorAll('tr'), 113 - i; 114 - 115 - for (i = 0; i < rows.length; i += 1) { 116 - rows[i].data = loadRowData(rows[i]); 117 - } 118 - } 119 - // sorts the table using the data for the ith column 120 - function sortByIndex(index, desc) { 121 - var key = cols[index].key, 122 - sorter = function(a, b) { 123 - a = a.data[key]; 124 - b = b.data[key]; 125 - return a < b ? -1 : a > b ? 1 : 0; 126 - }, 127 - finalSorter = sorter, 128 - tableBody = document.querySelector('.coverage-summary tbody'), 129 - rowNodes = tableBody.querySelectorAll('tr'), 130 - rows = [], 131 - i; 132 - 133 - if (desc) { 134 - finalSorter = function(a, b) { 135 - return -1 * sorter(a, b); 136 - }; 137 - } 138 - 139 - for (i = 0; i < rowNodes.length; i += 1) { 140 - rows.push(rowNodes[i]); 141 - tableBody.removeChild(rowNodes[i]); 142 - } 143 - 144 - rows.sort(finalSorter); 145 - 146 - for (i = 0; i < rows.length; i += 1) { 147 - tableBody.appendChild(rows[i]); 148 - } 149 - } 150 - // removes sort indicators for current column being sorted 151 - function removeSortIndicators() { 152 - var col = getNthColumn(currentSort.index), 153 - cls = col.className; 154 - 155 - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 156 - col.className = cls; 157 - } 158 - // adds sort indicators for current column being sorted 159 - function addSortIndicators() { 160 - getNthColumn(currentSort.index).className += currentSort.desc 161 - ? ' sorted-desc' 162 - : ' sorted'; 163 - } 164 - // adds event listeners for all sorter widgets 165 - function enableUI() { 166 - var i, 167 - el, 168 - ithSorter = function ithSorter(i) { 169 - var col = cols[i]; 170 - 171 - return function() { 172 - var desc = col.defaultDescSort; 173 - 174 - if (currentSort.index === i) { 175 - desc = !currentSort.desc; 176 - } 177 - sortByIndex(i, desc); 178 - removeSortIndicators(); 179 - currentSort.index = i; 180 - currentSort.desc = desc; 181 - addSortIndicators(); 182 - }; 183 - }; 184 - for (i = 0; i < cols.length; i += 1) { 185 - if (cols[i].sortable) { 186 - // add the click event handler on the th so users 187 - // dont have to click on those tiny arrows 188 - el = getNthColumn(i).querySelector('.sorter').parentElement; 189 - if (el.addEventListener) { 190 - el.addEventListener('click', ithSorter(i)); 191 - } else { 192 - el.attachEvent('onclick', ithSorter(i)); 193 - } 194 - } 195 - } 196 - } 197 - // adds sorting functionality to the UI 198 - return function() { 199 - if (!getTable()) { 200 - return; 201 - } 202 - cols = loadColumns(); 203 - loadData(); 204 - addSearchBox(); 205 - addSortIndicators(); 206 - enableUI(); 207 - }; 208 - })(); 209 - 210 - window.addEventListener('load', addSorting);
+224 -224
src/morphlex.ts
··· 1 - type IdSet = Set<string>; 2 - type IdMap = WeakMap<ReadonlyNode<Node>, IdSet>; 3 - type SensivityMap = WeakMap<ReadonlyNode<Node>, number>; 1 + type IdSet = Set<string> 2 + type IdMap = WeakMap<ReadonlyNode<Node>, IdSet> 3 + type SensivityMap = WeakMap<ReadonlyNode<Node>, number> 4 4 5 5 // Maps to a type that can only read properties 6 - type StrongReadonly<T> = { readonly [K in keyof T as T[K] extends Function ? never : K]: T[K] }; 6 + type StrongReadonly<T> = { readonly [K in keyof T as T[K] extends Function ? never : K]: T[K] } 7 7 8 - declare const brand: unique symbol; 9 - type Branded<T, B extends string> = T & { [brand]: B }; 8 + declare const brand: unique symbol 9 + type Branded<T, B extends string> = T & { [brand]: B } 10 10 11 - type NodeReferencePair<N extends Node> = Readonly<[N, ReadonlyNode<N>]>; 12 - type MatchingElementReferencePair<E extends Element> = Branded<NodeReferencePair<E>, "MatchingElementPair">; 11 + type NodeReferencePair<N extends Node> = Readonly<[N, ReadonlyNode<N>]> 12 + type MatchingElementReferencePair<E extends Element> = Branded<NodeReferencePair<E>, "MatchingElementPair"> 13 13 14 14 // Maps a Node to a type limited to read-only properties and methods for that Node 15 15 type ReadonlyNode<N extends Node> = 16 16 | N 17 17 | (StrongReadonly<N> & { 18 - readonly cloneNode: (deep: true) => Node; 19 - readonly childNodes: ReadonlyNodeList<ChildNode>; 20 - readonly querySelectorAll: (query: string) => ReadonlyNodeList<Element>; 21 - readonly parentElement: ReadonlyNode<Element> | null; 22 - readonly hasAttribute: (name: string) => boolean; 23 - readonly hasAttributes: () => boolean; 24 - readonly hasChildNodes: () => boolean; 25 - readonly children: ReadonlyNodeList<Element>; 26 - }); 18 + readonly cloneNode: (deep: true) => Node 19 + readonly childNodes: ReadonlyNodeList<ChildNode> 20 + readonly querySelectorAll: (query: string) => ReadonlyNodeList<Element> 21 + readonly parentElement: ReadonlyNode<Element> | null 22 + readonly hasAttribute: (name: string) => boolean 23 + readonly hasAttributes: () => boolean 24 + readonly hasChildNodes: () => boolean 25 + readonly children: ReadonlyNodeList<Element> 26 + }) 27 27 28 28 // Maps a node to a read-only node list of nodes of that type 29 29 type ReadonlyNodeList<N extends Node> = 30 30 | NodeListOf<N> 31 31 | { 32 - [Symbol.iterator](): IterableIterator<ReadonlyNode<N>>; 33 - readonly [index: number]: ReadonlyNode<N>; 34 - readonly length: NodeListOf<N>["length"]; 35 - }; 32 + [Symbol.iterator](): IterableIterator<ReadonlyNode<N>> 33 + readonly [index: number]: ReadonlyNode<N> 34 + readonly length: NodeListOf<N>["length"] 35 + } 36 36 37 37 interface Options { 38 - ignoreActiveValue?: boolean; 39 - preserveModifiedValues?: boolean; 40 - beforeNodeMorphed?: (node: Node, referenceNode: Node) => boolean; 41 - afterNodeMorphed?: (node: Node, referenceNode: Node) => void; 42 - beforeNodeAdded?: (node: Node) => boolean; 43 - afterNodeAdded?: (node: Node) => void; 44 - beforeNodeRemoved?: (node: Node) => boolean; 45 - afterNodeRemoved?: (node: Node) => void; 46 - beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) => boolean; 47 - afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) => void; 48 - beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) => boolean; 49 - afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) => void; 38 + ignoreActiveValue?: boolean 39 + preserveModifiedValues?: boolean 40 + beforeNodeMorphed?: (node: Node, referenceNode: Node) => boolean 41 + afterNodeMorphed?: (node: Node, referenceNode: Node) => void 42 + beforeNodeAdded?: (node: Node) => boolean 43 + afterNodeAdded?: (node: Node) => void 44 + beforeNodeRemoved?: (node: Node) => boolean 45 + afterNodeRemoved?: (node: Node) => void 46 + beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) => boolean 47 + afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) => void 48 + beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) => boolean 49 + afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) => void 50 50 } 51 51 52 52 export function morph(node: ChildNode, reference: ChildNode | string, options: Options = {}): void { 53 - if (typeof reference === "string") reference = parseChildNodeFromString(reference); 54 - new Morph(options).morph([node, reference]); 53 + if (typeof reference === "string") reference = parseChildNodeFromString(reference) 54 + new Morph(options).morph([node, reference]) 55 55 } 56 56 57 57 export function morphInner(element: Element, reference: Element | string, options: Options = {}): void { 58 - if (typeof reference === "string") reference = parseElementFromString(reference); 59 - new Morph(options).morphInner([element, reference]); 58 + if (typeof reference === "string") reference = parseElementFromString(reference) 59 + new Morph(options).morphInner([element, reference]) 60 60 } 61 61 62 62 function parseElementFromString(string: string): Element { 63 - const node = parseChildNodeFromString(string); 63 + const node = parseChildNodeFromString(string) 64 64 65 - if (isElement(node)) return node; 66 - else throw new Error("[Morphlex] The string was not a valid HTML element."); 65 + if (isElement(node)) return node 66 + else throw new Error("[Morphlex] The string was not a valid HTML element.") 67 67 } 68 68 69 69 function parseChildNodeFromString(string: string): ChildNode { 70 - const parser = new DOMParser(); 71 - const doc = parser.parseFromString(string, "text/html"); 70 + const parser = new DOMParser() 71 + const doc = parser.parseFromString(string, "text/html") 72 72 73 - if (doc.childNodes.length === 1) return doc.body.firstChild as ChildNode; 74 - else throw new Error("[Morphlex] The string was not a valid HTML node."); 73 + if (doc.childNodes.length === 1) return doc.body.firstChild as ChildNode 74 + else throw new Error("[Morphlex] The string was not a valid HTML node.") 75 75 } 76 76 77 77 class Morph { 78 - readonly #idMap: IdMap; 79 - readonly #sensivityMap: SensivityMap; 78 + readonly #idMap: IdMap 79 + readonly #sensivityMap: SensivityMap 80 80 81 - readonly #ignoreActiveValue: boolean; 82 - readonly #preserveModifiedValues: boolean; 83 - readonly #beforeNodeMorphed?: (node: Node, referenceNode: Node) => boolean; 84 - readonly #afterNodeMorphed?: (node: Node, referenceNode: Node) => void; 85 - readonly #beforeNodeAdded?: (node: Node) => boolean; 86 - readonly #afterNodeAdded?: (node: Node) => void; 87 - readonly #beforeNodeRemoved?: (node: Node) => boolean; 88 - readonly #afterNodeRemoved?: (node: Node) => void; 89 - readonly #beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) => boolean; 90 - readonly #afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) => void; 91 - readonly #beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) => boolean; 92 - readonly #afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) => void; 81 + readonly #ignoreActiveValue: boolean 82 + readonly #preserveModifiedValues: boolean 83 + readonly #beforeNodeMorphed?: (node: Node, referenceNode: Node) => boolean 84 + readonly #afterNodeMorphed?: (node: Node, referenceNode: Node) => void 85 + readonly #beforeNodeAdded?: (node: Node) => boolean 86 + readonly #afterNodeAdded?: (node: Node) => void 87 + readonly #beforeNodeRemoved?: (node: Node) => boolean 88 + readonly #afterNodeRemoved?: (node: Node) => void 89 + readonly #beforeAttributeUpdated?: (element: Element, attributeName: string, newValue: string | null) => boolean 90 + readonly #afterAttributeUpdated?: (element: Element, attributeName: string, previousValue: string | null) => void 91 + readonly #beforePropertyUpdated?: (node: Node, propertyName: PropertyKey, newValue: unknown) => boolean 92 + readonly #afterPropertyUpdated?: (node: Node, propertyName: PropertyKey, previousValue: unknown) => void 93 93 94 94 constructor(options: Options = {}) { 95 - this.#idMap = new WeakMap(); 96 - this.#sensivityMap = new WeakMap(); 95 + this.#idMap = new WeakMap() 96 + this.#sensivityMap = new WeakMap() 97 97 98 - this.#ignoreActiveValue = options.ignoreActiveValue || false; 99 - this.#preserveModifiedValues = options.preserveModifiedValues || false; 100 - this.#beforeNodeMorphed = options.beforeNodeMorphed; 101 - this.#afterNodeMorphed = options.afterNodeMorphed; 102 - this.#beforeNodeAdded = options.beforeNodeAdded; 103 - this.#afterNodeAdded = options.afterNodeAdded; 104 - this.#beforeNodeRemoved = options.beforeNodeRemoved; 105 - this.#afterNodeRemoved = options.afterNodeRemoved; 106 - this.#beforeAttributeUpdated = options.beforeAttributeUpdated; 107 - this.#afterAttributeUpdated = options.afterAttributeUpdated; 108 - this.#beforePropertyUpdated = options.beforePropertyUpdated; 109 - this.#afterPropertyUpdated = options.afterPropertyUpdated; 98 + this.#ignoreActiveValue = options.ignoreActiveValue || false 99 + this.#preserveModifiedValues = options.preserveModifiedValues || false 100 + this.#beforeNodeMorphed = options.beforeNodeMorphed 101 + this.#afterNodeMorphed = options.afterNodeMorphed 102 + this.#beforeNodeAdded = options.beforeNodeAdded 103 + this.#afterNodeAdded = options.afterNodeAdded 104 + this.#beforeNodeRemoved = options.beforeNodeRemoved 105 + this.#afterNodeRemoved = options.afterNodeRemoved 106 + this.#beforeAttributeUpdated = options.beforeAttributeUpdated 107 + this.#afterAttributeUpdated = options.afterAttributeUpdated 108 + this.#beforePropertyUpdated = options.beforePropertyUpdated 109 + this.#afterPropertyUpdated = options.afterPropertyUpdated 110 110 } 111 111 112 112 morph(pair: NodeReferencePair<ChildNode>): void { 113 113 this.#withAriaBusy(pair[0], () => { 114 - if (isParentNodePair(pair)) this.#buildMaps(pair); 115 - this.#morphNode(pair); 116 - }); 114 + if (isParentNodePair(pair)) this.#buildMaps(pair) 115 + this.#morphNode(pair) 116 + }) 117 117 } 118 118 119 119 morphInner(pair: NodeReferencePair<Element>): void { 120 120 this.#withAriaBusy(pair[0], () => { 121 121 if (isMatchingElementPair(pair)) { 122 - this.#buildMaps(pair); 123 - this.#morphMatchingElementContent(pair); 122 + this.#buildMaps(pair) 123 + this.#morphMatchingElementContent(pair) 124 124 } else { 125 - throw new Error("[Morphlex] You can only do an inner morph with matching elements."); 125 + throw new Error("[Morphlex] You can only do an inner morph with matching elements.") 126 126 } 127 - }); 127 + }) 128 128 } 129 129 130 130 #withAriaBusy(node: Node, block: () => void): void { 131 131 if (isElement(node)) { 132 - const originalAriaBusy = node.ariaBusy; 133 - node.ariaBusy = "true"; 134 - block(); 135 - node.ariaBusy = originalAriaBusy; 136 - } else block(); 132 + const originalAriaBusy = node.ariaBusy 133 + node.ariaBusy = "true" 134 + block() 135 + node.ariaBusy = originalAriaBusy 136 + } else block() 137 137 } 138 138 139 139 #buildMaps([node, reference]: NodeReferencePair<ParentNode>): void { 140 - this.#mapIdSets(node); 141 - this.#mapIdSets(reference); 142 - this.#mapSensivity(node); 140 + this.#mapIdSets(node) 141 + this.#mapIdSets(reference) 142 + this.#mapSensivity(node) 143 143 } 144 144 145 145 #mapSensivity(node: ReadonlyNode<ParentNode>): void { 146 - const sensitiveElements = node.querySelectorAll("audio,canvas,embed,iframe,input,object,textarea,video"); 146 + const sensitiveElements = node.querySelectorAll("audio,canvas,embed,iframe,input,object,textarea,video") 147 147 148 - const sensitiveElementsLength = sensitiveElements.length; 148 + const sensitiveElementsLength = sensitiveElements.length 149 149 for (let i = 0; i < sensitiveElementsLength; i++) { 150 - const sensitiveElement = sensitiveElements[i]; 151 - let sensivity = 0; 150 + const sensitiveElement = sensitiveElements[i] 151 + let sensivity = 0 152 152 153 153 if (isInput(sensitiveElement) || isTextArea(sensitiveElement)) { 154 - sensivity++; 154 + sensivity++ 155 155 156 - if (sensitiveElement.value !== sensitiveElement.defaultValue) sensivity++; 157 - if (sensitiveElement === document.activeElement) sensivity++; 156 + if (sensitiveElement.value !== sensitiveElement.defaultValue) sensivity++ 157 + if (sensitiveElement === document.activeElement) sensivity++ 158 158 } else { 159 - sensivity += 3; 159 + sensivity += 3 160 160 161 161 if (isMedia(sensitiveElement) && !sensitiveElement.ended) { 162 - if (!sensitiveElement.paused) sensivity++; 163 - if (sensitiveElement.currentTime > 0) sensivity++; 162 + if (!sensitiveElement.paused) sensivity++ 163 + if (sensitiveElement.currentTime > 0) sensivity++ 164 164 } 165 165 } 166 166 167 - let current: ReadonlyNode<Element> | null = sensitiveElement; 167 + let current: ReadonlyNode<Element> | null = sensitiveElement 168 168 while (current) { 169 - this.#sensivityMap.set(current, (this.#sensivityMap.get(current) || 0) + sensivity); 170 - if (current === node) break; 171 - current = current.parentElement; 169 + this.#sensivityMap.set(current, (this.#sensivityMap.get(current) || 0) + sensivity) 170 + if (current === node) break 171 + current = current.parentElement 172 172 } 173 173 } 174 174 } 175 175 176 176 // For each node with an ID, push that ID into the IdSet on the IdMap, for each of its parent elements. 177 177 #mapIdSets(node: ReadonlyNode<ParentNode>): void { 178 - const elementsWithIds = node.querySelectorAll("[id]"); 178 + const elementsWithIds = node.querySelectorAll("[id]") 179 179 180 - const elementsWithIdsLength = elementsWithIds.length; 180 + const elementsWithIdsLength = elementsWithIds.length 181 181 for (let i = 0; i < elementsWithIdsLength; i++) { 182 - const elementWithId = elementsWithIds[i]; 183 - const id = elementWithId.id; 182 + const elementWithId = elementsWithIds[i] 183 + const id = elementWithId.id 184 184 185 185 // Ignore empty IDs 186 - if (id === "") continue; 186 + if (id === "") continue 187 187 188 - let current: ReadonlyNode<Element> | null = elementWithId; 188 + let current: ReadonlyNode<Element> | null = elementWithId 189 189 190 190 while (current) { 191 - const idSet: IdSet | undefined = this.#idMap.get(current); 192 - idSet ? idSet.add(id) : this.#idMap.set(current, new Set([id])); 193 - if (current === node) break; 194 - current = current.parentElement; 191 + const idSet: IdSet | undefined = this.#idMap.get(current) 192 + idSet ? idSet.add(id) : this.#idMap.set(current, new Set([id])) 193 + if (current === node) break 194 + current = current.parentElement 195 195 } 196 196 } 197 197 } 198 198 199 199 // This is where we actually morph the nodes. The `morph` function (above) exists only to set up the `idMap`. 200 200 #morphNode(pair: NodeReferencePair<ChildNode>): void { 201 - if (isMatchingElementPair(pair)) this.#morphMatchingElementNode(pair); 202 - else this.#morphOtherNode(pair); 201 + if (isMatchingElementPair(pair)) this.#morphMatchingElementNode(pair) 202 + else this.#morphOtherNode(pair) 203 203 } 204 204 205 205 #morphMatchingElementNode(pair: MatchingElementReferencePair<Element>): void { 206 - const [node, reference] = pair; 206 + const [node, reference] = pair 207 207 208 - if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) return; 208 + if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) return 209 209 210 - if (node.hasAttributes() || reference.hasAttributes()) this.#morphAttributes(pair); 210 + if (node.hasAttributes() || reference.hasAttributes()) this.#morphAttributes(pair) 211 211 212 212 // TODO: Should use a branded pair here. 213 - this.#morphMatchingElementContent(pair); 213 + this.#morphMatchingElementContent(pair) 214 214 215 - this.#afterNodeMorphed?.(node, writableNode(reference)); 215 + this.#afterNodeMorphed?.(node, writableNode(reference)) 216 216 } 217 217 218 218 #morphOtherNode([node, reference]: NodeReferencePair<ChildNode>): void { 219 - if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) return; 219 + if (!(this.#beforeNodeMorphed?.(node, writableNode(reference)) ?? true)) return 220 220 221 221 if (node.nodeType === reference.nodeType && node.nodeValue !== null && reference.nodeValue !== null) { 222 222 // Handle text nodes, comments, and CDATA sections. 223 - this.#updateProperty(node, "nodeValue", reference.nodeValue); 224 - } else this.#replaceNode(node, reference.cloneNode(true)); 223 + this.#updateProperty(node, "nodeValue", reference.nodeValue) 224 + } else this.#replaceNode(node, reference.cloneNode(true)) 225 225 226 - this.#afterNodeMorphed?.(node, writableNode(reference)); 226 + this.#afterNodeMorphed?.(node, writableNode(reference)) 227 227 } 228 228 229 229 #morphMatchingElementContent(pair: MatchingElementReferencePair<Element>): void { 230 - const [node, reference] = pair; 230 + const [node, reference] = pair 231 231 232 232 if (isHead(node)) { 233 233 // We can pass the reference as a head here becuase we know it's the same as the node. 234 - this.#morphHeadContents(pair as MatchingElementReferencePair<HTMLHeadElement>); 235 - } else if (node.hasChildNodes() || reference.hasChildNodes()) this.#morphChildNodes(pair); 234 + this.#morphHeadContents(pair as MatchingElementReferencePair<HTMLHeadElement>) 235 + } else if (node.hasChildNodes() || reference.hasChildNodes()) this.#morphChildNodes(pair) 236 236 } 237 237 238 238 #morphHeadContents([node, reference]: MatchingElementReferencePair<HTMLHeadElement>): void { 239 - const refChildNodesMap: Map<string, ReadonlyNode<Element>> = new Map(); 239 + const refChildNodesMap: Map<string, ReadonlyNode<Element>> = new Map() 240 240 241 241 // Generate a map of the reference head element’s child nodes, keyed by their outerHTML. 242 - const referenceChildrenLength = reference.children.length; 242 + const referenceChildrenLength = reference.children.length 243 243 for (let i = 0; i < referenceChildrenLength; i++) { 244 - const child = reference.children[i]; 245 - refChildNodesMap.set(child.outerHTML, child); 244 + const child = reference.children[i] 245 + refChildNodesMap.set(child.outerHTML, child) 246 246 } 247 247 248 248 // Iterate backwards to safely remove children without affecting indices 249 249 for (let i = node.children.length - 1; i >= 0; i--) { 250 - const child = node.children[i]; 251 - const key = child.outerHTML; 252 - const refChild = refChildNodesMap.get(key); 250 + const child = node.children[i] 251 + const key = child.outerHTML 252 + const refChild = refChildNodesMap.get(key) 253 253 254 254 // If the child is in the reference map already, we don't need to add it later. 255 255 // If it's not in the map, we need to remove it from the node. 256 - refChild ? refChildNodesMap.delete(key) : this.#removeNode(child); 256 + refChild ? refChildNodesMap.delete(key) : this.#removeNode(child) 257 257 } 258 258 259 259 // Any remaining nodes in the map should be appended to the head. 260 - for (const refChild of refChildNodesMap.values()) this.#appendChild(node, refChild.cloneNode(true)); 260 + for (const refChild of refChildNodesMap.values()) this.#appendChild(node, refChild.cloneNode(true)) 261 261 } 262 262 263 263 #morphAttributes([element, reference]: MatchingElementReferencePair<Element>): void { 264 264 // Remove any excess attributes from the element that aren’t present in the reference. 265 265 for (const { name, value } of element.attributes) { 266 266 if (!reference.hasAttribute(name) && (this.#beforeAttributeUpdated?.(element, name, null) ?? true)) { 267 - element.removeAttribute(name); 268 - this.#afterAttributeUpdated?.(element, name, value); 267 + element.removeAttribute(name) 268 + this.#afterAttributeUpdated?.(element, name, value) 269 269 } 270 270 } 271 271 272 272 // Copy attributes from the reference to the element, if they don’t already match. 273 273 for (const { name, value } of reference.attributes) { 274 - const previousValue = element.getAttribute(name); 274 + const previousValue = element.getAttribute(name) 275 275 if (previousValue !== value && (this.#beforeAttributeUpdated?.(element, name, value) ?? true)) { 276 - element.setAttribute(name, value); 277 - this.#afterAttributeUpdated?.(element, name, previousValue); 276 + element.setAttribute(name, value) 277 + this.#afterAttributeUpdated?.(element, name, previousValue) 278 278 } 279 279 } 280 280 281 281 // For certain types of elements, we need to do some extra work to ensure 282 282 // the element’s state matches the reference elements’ state. 283 283 if (isInput(element) && isInput(reference)) { 284 - this.#updateProperty(element, "checked", reference.checked); 285 - this.#updateProperty(element, "disabled", reference.disabled); 286 - this.#updateProperty(element, "indeterminate", reference.indeterminate); 284 + this.#updateProperty(element, "checked", reference.checked) 285 + this.#updateProperty(element, "disabled", reference.disabled) 286 + this.#updateProperty(element, "indeterminate", reference.indeterminate) 287 287 if ( 288 288 element.type !== "file" && 289 289 !(this.#ignoreActiveValue && document.activeElement === element) && 290 290 !(this.#preserveModifiedValues && element.name === reference.name && element.value !== element.defaultValue) 291 291 ) { 292 - this.#updateProperty(element, "value", reference.value); 292 + this.#updateProperty(element, "value", reference.value) 293 293 } 294 294 } else if (isOption(element) && isOption(reference)) { 295 - this.#updateProperty(element, "selected", reference.selected); 295 + this.#updateProperty(element, "selected", reference.selected) 296 296 } else if ( 297 297 isTextArea(element) && 298 298 isTextArea(reference) && 299 299 !(this.#ignoreActiveValue && document.activeElement === element) && 300 300 !(this.#preserveModifiedValues && element.name === reference.name && element.value !== element.defaultValue) 301 301 ) { 302 - this.#updateProperty(element, "value", reference.value); 302 + this.#updateProperty(element, "value", reference.value) 303 303 304 - const text = element.firstElementChild; 305 - if (text) this.#updateProperty(text, "textContent", reference.value); 304 + const text = element.firstElementChild 305 + if (text) this.#updateProperty(text, "textContent", reference.value) 306 306 } 307 307 } 308 308 309 309 // Iterates over the child nodes of the reference element, morphing the main element’s child nodes to match. 310 310 #morphChildNodes(pair: MatchingElementReferencePair<Element>): void { 311 - const [element, reference] = pair; 311 + const [element, reference] = pair 312 312 313 - const childNodes = element.childNodes; 314 - const refChildNodes = reference.childNodes; 313 + const childNodes = element.childNodes 314 + const refChildNodes = reference.childNodes 315 315 316 316 for (let i = 0; i < refChildNodes.length; i++) { 317 - const child = childNodes[i] as ChildNode | null; 318 - const refChild = refChildNodes[i] as ReadonlyNode<ChildNode> | null; 317 + const child = childNodes[i] as ChildNode | null 318 + const refChild = refChildNodes[i] as ReadonlyNode<ChildNode> | null 319 319 320 320 if (child && refChild) { 321 - const pair: NodeReferencePair<ChildNode> = [child, refChild]; 321 + const pair: NodeReferencePair<ChildNode> = [child, refChild] 322 322 323 323 if (isMatchingElementPair(pair)) { 324 324 if (isHead(pair[0])) { 325 - this.#morphHeadContents(pair as MatchingElementReferencePair<HTMLHeadElement>); 325 + this.#morphHeadContents(pair as MatchingElementReferencePair<HTMLHeadElement>) 326 326 } else { 327 - this.#morphChildElement(pair, element); 327 + this.#morphChildElement(pair, element) 328 328 } 329 - } else this.#morphOtherNode(pair); 329 + } else this.#morphOtherNode(pair) 330 330 } else if (refChild) { 331 - this.#appendChild(element, refChild.cloneNode(true)); 331 + this.#appendChild(element, refChild.cloneNode(true)) 332 332 } else if (child) { 333 - this.#removeNode(child); 333 + this.#removeNode(child) 334 334 } 335 335 } 336 336 337 337 // Clean up any excess nodes that may be left over 338 338 while (childNodes.length > refChildNodes.length) { 339 - const child = element.lastChild; 340 - if (child) this.#removeNode(child); 339 + const child = element.lastChild 340 + if (child) this.#removeNode(child) 341 341 } 342 342 } 343 343 344 344 #morphChildElement([child, reference]: MatchingElementReferencePair<Element>, parent: Element): void { 345 - if (!(this.#beforeNodeMorphed?.(child, writableNode(reference)) ?? true)) return; 345 + if (!(this.#beforeNodeMorphed?.(child, writableNode(reference)) ?? true)) return 346 346 347 - const refIdSet = this.#idMap.get(reference); 347 + const refIdSet = this.#idMap.get(reference) 348 348 349 349 // Generate the array in advance of the loop 350 - const refSetArray = refIdSet ? [...refIdSet] : []; 350 + const refSetArray = refIdSet ? [...refIdSet] : [] 351 351 352 - let currentNode: ChildNode | null = child; 353 - let nextMatchByTagName: ChildNode | null = null; 352 + let currentNode: ChildNode | null = child 353 + let nextMatchByTagName: ChildNode | null = null 354 354 355 355 // Try find a match by idSet, while also looking out for the next best match by tagName. 356 356 while (currentNode) { 357 357 if (isElement(currentNode)) { 358 - const id = currentNode.id; 358 + const id = currentNode.id 359 359 360 360 if (!nextMatchByTagName && currentNode.localName === reference.localName) { 361 - nextMatchByTagName = currentNode; 361 + nextMatchByTagName = currentNode 362 362 } 363 363 364 364 if (id !== "") { 365 365 if (id === reference.id) { 366 - this.#insertBefore(parent, currentNode, child); 367 - return this.#morphNode([currentNode, reference]); 366 + this.#insertBefore(parent, currentNode, child) 367 + return this.#morphNode([currentNode, reference]) 368 368 } else { 369 - const currentIdSet = this.#idMap.get(currentNode); 369 + const currentIdSet = this.#idMap.get(currentNode) 370 370 371 371 if (currentIdSet && refSetArray.some((it) => currentIdSet.has(it))) { 372 - this.#insertBefore(parent, currentNode, child); 373 - return this.#morphNode([currentNode, reference]); 372 + this.#insertBefore(parent, currentNode, child) 373 + return this.#morphNode([currentNode, reference]) 374 374 } 375 375 } 376 376 } 377 377 } 378 378 379 - currentNode = currentNode.nextSibling; 379 + currentNode = currentNode.nextSibling 380 380 } 381 381 382 382 if (nextMatchByTagName) { 383 - this.#insertBefore(parent, nextMatchByTagName, child); 384 - this.#morphNode([nextMatchByTagName, reference]); 383 + this.#insertBefore(parent, nextMatchByTagName, child) 384 + this.#morphNode([nextMatchByTagName, reference]) 385 385 } else { 386 - const newNode = reference.cloneNode(true); 386 + const newNode = reference.cloneNode(true) 387 387 if (this.#beforeNodeAdded?.(newNode) ?? true) { 388 - this.#insertBefore(parent, newNode, child); 389 - this.#afterNodeAdded?.(newNode); 388 + this.#insertBefore(parent, newNode, child) 389 + this.#afterNodeAdded?.(newNode) 390 390 } 391 391 } 392 392 393 - this.#afterNodeMorphed?.(child, writableNode(reference)); 393 + this.#afterNodeMorphed?.(child, writableNode(reference)) 394 394 } 395 395 396 396 #updateProperty<N extends Node, P extends keyof N>(node: N, propertyName: P, newValue: N[P]): void { 397 - const previousValue = node[propertyName]; 397 + const previousValue = node[propertyName] 398 398 399 399 if (previousValue !== newValue && (this.#beforePropertyUpdated?.(node, propertyName, newValue) ?? true)) { 400 - node[propertyName] = newValue; 401 - this.#afterPropertyUpdated?.(node, propertyName, previousValue); 400 + node[propertyName] = newValue 401 + this.#afterPropertyUpdated?.(node, propertyName, previousValue) 402 402 } 403 403 } 404 404 405 405 #replaceNode(node: ChildNode, newNode: Node): void { 406 406 if ((this.#beforeNodeRemoved?.(node) ?? true) && (this.#beforeNodeAdded?.(newNode) ?? true)) { 407 - node.replaceWith(newNode); 408 - this.#afterNodeAdded?.(newNode); 409 - this.#afterNodeRemoved?.(node); 407 + node.replaceWith(newNode) 408 + this.#afterNodeAdded?.(newNode) 409 + this.#afterNodeRemoved?.(node) 410 410 } 411 411 } 412 412 413 413 #insertBefore(parent: ParentNode, node: Node, insertionPoint: ChildNode): void { 414 - if (node === insertionPoint) return; 414 + if (node === insertionPoint) return 415 415 416 416 if (isElement(node)) { 417 - const sensitivity = this.#sensivityMap.get(node) ?? 0; 417 + const sensitivity = this.#sensivityMap.get(node) ?? 0 418 418 419 419 if (sensitivity > 0) { 420 - let previousNode = node.previousSibling; 420 + let previousNode = node.previousSibling 421 421 422 422 while (previousNode) { 423 - const previousNodeSensitivity = this.#sensivityMap.get(previousNode) ?? 0; 423 + const previousNodeSensitivity = this.#sensivityMap.get(previousNode) ?? 0 424 424 425 425 if (previousNodeSensitivity < sensitivity) { 426 - parent.insertBefore(previousNode, node.nextSibling); 426 + parent.insertBefore(previousNode, node.nextSibling) 427 427 428 - if (previousNode === insertionPoint) return; 429 - previousNode = node.previousSibling; 430 - } else break; 428 + if (previousNode === insertionPoint) return 429 + previousNode = node.previousSibling 430 + } else break 431 431 } 432 432 } 433 433 } 434 434 435 - parent.insertBefore(node, insertionPoint); 435 + parent.insertBefore(node, insertionPoint) 436 436 } 437 437 438 438 #appendChild(node: ParentNode, newNode: Node): void { 439 439 if (this.#beforeNodeAdded?.(newNode) ?? true) { 440 - node.appendChild(newNode); 441 - this.#afterNodeAdded?.(newNode); 440 + node.appendChild(newNode) 441 + this.#afterNodeAdded?.(newNode) 442 442 } 443 443 } 444 444 445 445 #removeNode(node: ChildNode): void { 446 446 if (this.#beforeNodeRemoved?.(node) ?? true) { 447 - node.remove(); 448 - this.#afterNodeRemoved?.(node); 447 + node.remove() 448 + this.#afterNodeRemoved?.(node) 449 449 } 450 450 } 451 451 } 452 452 453 453 function writableNode<N extends Node>(node: ReadonlyNode<N>): N { 454 - return node as N; 454 + return node as N 455 455 } 456 456 457 457 function isMatchingElementPair(pair: NodeReferencePair<Node>): pair is MatchingElementReferencePair<Element> { 458 - const [a, b] = pair; 459 - return isElement(a) && isElement(b) && a.localName === b.localName; 458 + const [a, b] = pair 459 + return isElement(a) && isElement(b) && a.localName === b.localName 460 460 } 461 461 462 462 function isParentNodePair(pair: NodeReferencePair<Node>): pair is NodeReferencePair<ParentNode> { 463 - return isParentNode(pair[0]) && isParentNode(pair[1]); 463 + return isParentNode(pair[0]) && isParentNode(pair[1]) 464 464 } 465 465 466 - function isElement(node: Node): node is Element; 467 - function isElement(node: ReadonlyNode<Node>): node is ReadonlyNode<Element>; 466 + function isElement(node: Node): node is Element 467 + function isElement(node: ReadonlyNode<Node>): node is ReadonlyNode<Element> 468 468 function isElement(node: Node | ReadonlyNode<Node>): boolean { 469 - return node.nodeType === 1; 469 + return node.nodeType === 1 470 470 } 471 471 472 - function isMedia(element: Element): element is HTMLMediaElement; 473 - function isMedia(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLMediaElement>; 472 + function isMedia(element: Element): element is HTMLMediaElement 473 + function isMedia(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLMediaElement> 474 474 function isMedia(element: Element | ReadonlyNode<Element>): boolean { 475 - return element.localName === "video" || element.localName === "audio"; 475 + return element.localName === "video" || element.localName === "audio" 476 476 } 477 477 478 - function isInput(element: Element): element is HTMLInputElement; 479 - function isInput(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLInputElement>; 478 + function isInput(element: Element): element is HTMLInputElement 479 + function isInput(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLInputElement> 480 480 function isInput(element: Element | ReadonlyNode<Element>): boolean { 481 - return element.localName === "input"; 481 + return element.localName === "input" 482 482 } 483 483 484 - function isOption(element: Element): element is HTMLOptionElement; 485 - function isOption(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLOptionElement>; 484 + function isOption(element: Element): element is HTMLOptionElement 485 + function isOption(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLOptionElement> 486 486 function isOption(element: Element | ReadonlyNode<Element>): boolean { 487 - return element.localName === "option"; 487 + return element.localName === "option" 488 488 } 489 489 490 - function isTextArea(element: Element): element is HTMLTextAreaElement; 491 - function isTextArea(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLTextAreaElement>; 490 + function isTextArea(element: Element): element is HTMLTextAreaElement 491 + function isTextArea(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLTextAreaElement> 492 492 function isTextArea(element: Element | ReadonlyNode<Element>): boolean { 493 - return element.localName === "textarea"; 493 + return element.localName === "textarea" 494 494 } 495 495 496 - function isHead(element: Element): element is HTMLHeadElement; 497 - function isHead(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLHeadElement>; 496 + function isHead(element: Element): element is HTMLHeadElement 497 + function isHead(element: ReadonlyNode<Element>): element is ReadonlyNode<HTMLHeadElement> 498 498 function isHead(element: Element | ReadonlyNode<Element>): boolean { 499 - return element.localName === "head"; 499 + return element.localName === "head" 500 500 } 501 501 502 - const parentNodeTypes = new Set([1, 9, 11]); 502 + const parentNodeTypes = new Set([1, 9, 11]) 503 503 504 - function isParentNode(node: Node): node is ParentNode; 505 - function isParentNode(node: ReadonlyNode<Node>): node is ReadonlyNode<ParentNode>; 504 + function isParentNode(node: Node): node is ParentNode 505 + function isParentNode(node: ReadonlyNode<Node>): node is ReadonlyNode<ParentNode> 506 506 function isParentNode(node: Node | ReadonlyNode<Node>): boolean { 507 - return parentNodeTypes.has(node.nodeType); 507 + return parentNodeTypes.has(node.nodeType) 508 508 }
+903 -903
test/morphlex-coverage.test.ts
··· 1 - import { describe, it, expect, beforeEach, afterEach } from "vitest"; 2 - import { morph, morphInner } from "../src/morphlex"; 1 + import { describe, it, expect, beforeEach, afterEach } from "vitest" 2 + import { morph, morphInner } from "../src/morphlex" 3 3 4 4 describe("Morphlex - Coverage Tests", () => { 5 - let container: HTMLElement; 5 + let container: HTMLElement 6 6 7 7 beforeEach(() => { 8 - container = document.createElement("div"); 9 - document.body.appendChild(container); 10 - }); 8 + container = document.createElement("div") 9 + document.body.appendChild(container) 10 + }) 11 11 12 12 afterEach(() => { 13 13 if (container && container.parentNode) { 14 - container.parentNode.removeChild(container); 14 + container.parentNode.removeChild(container) 15 15 } 16 - }); 16 + }) 17 17 18 18 describe("String parsing error cases", () => { 19 19 it("should throw error when parseElementFromString receives non-element string", () => { 20 - const div = document.createElement("div"); 21 - container.appendChild(div); 20 + const div = document.createElement("div") 21 + container.appendChild(div) 22 22 23 23 // Text node is not an element 24 24 expect(() => { 25 - morphInner(div, "Just text"); 26 - }).toThrow("[Morphlex] The string was not a valid HTML element."); 27 - }); 25 + morphInner(div, "Just text") 26 + }).toThrow("[Morphlex] The string was not a valid HTML element.") 27 + }) 28 28 29 29 it("should parse multiple elements as valid HTML (they go into body)", () => { 30 - const div = document.createElement("div"); 31 - container.appendChild(div); 30 + const div = document.createElement("div") 31 + container.appendChild(div) 32 32 33 33 // Multiple root nodes actually work because DOMParser wraps them in body 34 34 // This test just verifies the parsing works 35 - const reference = "<div>Content</div>"; 36 - morph(div, reference); 37 - expect(div.textContent).toBe("Content"); 38 - }); 35 + const reference = "<div>Content</div>" 36 + morph(div, reference) 37 + expect(div.textContent).toBe("Content") 38 + }) 39 39 40 40 it("should throw error when morphInner called with non-matching elements", () => { 41 - const div = document.createElement("div"); 42 - const span = document.createElement("span"); 43 - container.appendChild(div); 41 + const div = document.createElement("div") 42 + const span = document.createElement("span") 43 + container.appendChild(div) 44 44 45 45 expect(() => { 46 - morphInner(div, span); 47 - }).toThrow("[Morphlex] You can only do an inner morph with matching elements."); 48 - }); 49 - }); 46 + morphInner(div, span) 47 + }).toThrow("[Morphlex] You can only do an inner morph with matching elements.") 48 + }) 49 + }) 50 50 51 51 describe("ariaBusy handling", () => { 52 52 it("should set and restore ariaBusy on element during morph", () => { 53 - const div = document.createElement("div"); 54 - div.ariaBusy = "false"; 55 - const span = document.createElement("span"); 56 - div.appendChild(span); 53 + const div = document.createElement("div") 54 + div.ariaBusy = "false" 55 + const span = document.createElement("span") 56 + div.appendChild(span) 57 57 58 - const reference = document.createElement("div"); 59 - const refSpan = document.createElement("span"); 60 - refSpan.textContent = "Updated"; 61 - reference.appendChild(refSpan); 58 + const reference = document.createElement("div") 59 + const refSpan = document.createElement("span") 60 + refSpan.textContent = "Updated" 61 + reference.appendChild(refSpan) 62 62 63 - let ariaBusyDuringMorph: string | null = null; 63 + let ariaBusyDuringMorph: string | null = null 64 64 morph(div, reference, { 65 65 afterNodeMorphed: (node) => { 66 66 if (node === span) { 67 - ariaBusyDuringMorph = div.ariaBusy; 67 + ariaBusyDuringMorph = div.ariaBusy 68 68 } 69 69 }, 70 - }); 70 + }) 71 71 72 72 // ariaBusy should be set to "true" during morph and restored after 73 - expect(ariaBusyDuringMorph).toBe("true"); 74 - expect(div.ariaBusy).toBe("false"); 75 - }); 73 + expect(ariaBusyDuringMorph).toBe("true") 74 + expect(div.ariaBusy).toBe("false") 75 + }) 76 76 77 77 it("should handle ariaBusy for non-element nodes", () => { 78 - const parent = document.createElement("div"); 79 - const textNode = document.createTextNode("Original"); 80 - parent.appendChild(textNode); 78 + const parent = document.createElement("div") 79 + const textNode = document.createTextNode("Original") 80 + parent.appendChild(textNode) 81 81 82 - const referenceParent = document.createElement("div"); 83 - const refTextNode = document.createTextNode("Updated"); 84 - referenceParent.appendChild(refTextNode); 82 + const referenceParent = document.createElement("div") 83 + const refTextNode = document.createTextNode("Updated") 84 + referenceParent.appendChild(refTextNode) 85 85 86 - morph(parent, referenceParent); 86 + morph(parent, referenceParent) 87 87 88 - expect(parent.textContent).toBe("Updated"); 89 - }); 90 - }); 88 + expect(parent.textContent).toBe("Updated") 89 + }) 90 + }) 91 91 92 92 describe("Sensitivity mapping for media elements", () => { 93 93 it("should handle media elements with various states", () => { 94 - const parent = document.createElement("div"); 95 - const video = document.createElement("video"); 96 - video.id = "video1"; 97 - parent.appendChild(video); 94 + const parent = document.createElement("div") 95 + const video = document.createElement("video") 96 + video.id = "video1" 97 + parent.appendChild(video) 98 98 99 - const reference = document.createElement("div"); 100 - const refVideo = document.createElement("video"); 101 - refVideo.id = "video1"; 102 - refVideo.setAttribute("src", "test.mp4"); 103 - reference.appendChild(refVideo); 99 + const reference = document.createElement("div") 100 + const refVideo = document.createElement("video") 101 + refVideo.id = "video1" 102 + refVideo.setAttribute("src", "test.mp4") 103 + reference.appendChild(refVideo) 104 104 105 - morph(parent, reference); 105 + morph(parent, reference) 106 106 107 - expect(parent.querySelector("video")).toBeTruthy(); 108 - }); 107 + expect(parent.querySelector("video")).toBeTruthy() 108 + }) 109 109 110 110 it("should handle audio elements", () => { 111 - const parent = document.createElement("div"); 112 - const audio = document.createElement("audio"); 113 - audio.id = "audio1"; 114 - parent.appendChild(audio); 111 + const parent = document.createElement("div") 112 + const audio = document.createElement("audio") 113 + audio.id = "audio1" 114 + parent.appendChild(audio) 115 115 116 - const reference = document.createElement("div"); 117 - const refAudio = document.createElement("audio"); 118 - refAudio.id = "audio1"; 119 - refAudio.setAttribute("src", "test.mp3"); 120 - reference.appendChild(refAudio); 116 + const reference = document.createElement("div") 117 + const refAudio = document.createElement("audio") 118 + refAudio.id = "audio1" 119 + refAudio.setAttribute("src", "test.mp3") 120 + reference.appendChild(refAudio) 121 121 122 - morph(parent, reference); 122 + morph(parent, reference) 123 123 124 - expect(parent.querySelector("audio")).toBeTruthy(); 125 - }); 124 + expect(parent.querySelector("audio")).toBeTruthy() 125 + }) 126 126 127 127 it("should handle canvas elements", () => { 128 - const parent = document.createElement("div"); 129 - const canvas = document.createElement("canvas"); 130 - canvas.id = "canvas1"; 131 - parent.appendChild(canvas); 128 + const parent = document.createElement("div") 129 + const canvas = document.createElement("canvas") 130 + canvas.id = "canvas1" 131 + parent.appendChild(canvas) 132 132 133 - const reference = document.createElement("div"); 134 - const refCanvas = document.createElement("canvas"); 135 - refCanvas.id = "canvas1"; 136 - refCanvas.width = 800; 137 - reference.appendChild(refCanvas); 133 + const reference = document.createElement("div") 134 + const refCanvas = document.createElement("canvas") 135 + refCanvas.id = "canvas1" 136 + refCanvas.width = 800 137 + reference.appendChild(refCanvas) 138 138 139 - morph(parent, reference); 139 + morph(parent, reference) 140 140 141 - expect(parent.querySelector("canvas")).toBeTruthy(); 142 - }); 141 + expect(parent.querySelector("canvas")).toBeTruthy() 142 + }) 143 143 144 144 it("should handle embed elements", () => { 145 - const parent = document.createElement("div"); 146 - const embed = document.createElement("embed"); 147 - embed.id = "embed1"; 148 - parent.appendChild(embed); 145 + const parent = document.createElement("div") 146 + const embed = document.createElement("embed") 147 + embed.id = "embed1" 148 + parent.appendChild(embed) 149 149 150 - const reference = document.createElement("div"); 151 - const refEmbed = document.createElement("embed"); 152 - refEmbed.id = "embed1"; 153 - refEmbed.setAttribute("src", "test.pdf"); 154 - reference.appendChild(refEmbed); 150 + const reference = document.createElement("div") 151 + const refEmbed = document.createElement("embed") 152 + refEmbed.id = "embed1" 153 + refEmbed.setAttribute("src", "test.pdf") 154 + reference.appendChild(refEmbed) 155 155 156 - morph(parent, reference); 156 + morph(parent, reference) 157 157 158 - expect(parent.querySelector("embed")).toBeTruthy(); 159 - }); 158 + expect(parent.querySelector("embed")).toBeTruthy() 159 + }) 160 160 161 161 it("should handle iframe elements", () => { 162 - const parent = document.createElement("div"); 163 - const iframe = document.createElement("iframe"); 164 - iframe.id = "iframe1"; 165 - parent.appendChild(iframe); 162 + const parent = document.createElement("div") 163 + const iframe = document.createElement("iframe") 164 + iframe.id = "iframe1" 165 + parent.appendChild(iframe) 166 166 167 - const reference = document.createElement("div"); 168 - const refIframe = document.createElement("iframe"); 169 - refIframe.id = "iframe1"; 170 - refIframe.setAttribute("src", "test.html"); 171 - reference.appendChild(refIframe); 167 + const reference = document.createElement("div") 168 + const refIframe = document.createElement("iframe") 169 + refIframe.id = "iframe1" 170 + refIframe.setAttribute("src", "test.html") 171 + reference.appendChild(refIframe) 172 172 173 - morph(parent, reference); 173 + morph(parent, reference) 174 174 175 - expect(parent.querySelector("iframe")).toBeTruthy(); 176 - }); 175 + expect(parent.querySelector("iframe")).toBeTruthy() 176 + }) 177 177 178 178 it("should handle object elements", () => { 179 - const parent = document.createElement("div"); 180 - const object = document.createElement("object"); 181 - object.id = "object1"; 182 - parent.appendChild(object); 179 + const parent = document.createElement("div") 180 + const object = document.createElement("object") 181 + object.id = "object1" 182 + parent.appendChild(object) 183 183 184 - const reference = document.createElement("div"); 185 - const refObject = document.createElement("object"); 186 - refObject.id = "object1"; 187 - refObject.setAttribute("data", "test.pdf"); 188 - reference.appendChild(refObject); 184 + const reference = document.createElement("div") 185 + const refObject = document.createElement("object") 186 + refObject.id = "object1" 187 + refObject.setAttribute("data", "test.pdf") 188 + reference.appendChild(refObject) 189 189 190 - morph(parent, reference); 190 + morph(parent, reference) 191 191 192 - expect(parent.querySelector("object")).toBeTruthy(); 193 - }); 192 + expect(parent.querySelector("object")).toBeTruthy() 193 + }) 194 194 195 195 it("should handle input as active element", () => { 196 - const parent = document.createElement("div"); 197 - container.appendChild(parent); 196 + const parent = document.createElement("div") 197 + container.appendChild(parent) 198 198 199 - const input = document.createElement("input"); 200 - input.id = "input1"; 201 - input.value = "test"; 202 - parent.appendChild(input); 199 + const input = document.createElement("input") 200 + input.id = "input1" 201 + input.value = "test" 202 + parent.appendChild(input) 203 203 204 204 // Focus the input to make it active 205 - input.focus(); 205 + input.focus() 206 206 207 - const reference = document.createElement("div"); 208 - const refInput = document.createElement("input"); 209 - refInput.id = "input1"; 210 - refInput.value = "updated"; 211 - reference.appendChild(refInput); 207 + const reference = document.createElement("div") 208 + const refInput = document.createElement("input") 209 + refInput.id = "input1" 210 + refInput.value = "updated" 211 + reference.appendChild(refInput) 212 212 213 - morph(parent, reference, { ignoreActiveValue: true }); 213 + morph(parent, reference, { ignoreActiveValue: true }) 214 214 215 215 // Value should be preserved because input is active 216 - expect(input.value).toBe("test"); 217 - }); 216 + expect(input.value).toBe("test") 217 + }) 218 218 219 219 it("should handle textarea as active element", () => { 220 - const parent = document.createElement("div"); 221 - container.appendChild(parent); 220 + const parent = document.createElement("div") 221 + container.appendChild(parent) 222 222 223 - const textarea = document.createElement("textarea"); 224 - textarea.id = "textarea1"; 225 - textarea.value = "original"; 226 - parent.appendChild(textarea); 223 + const textarea = document.createElement("textarea") 224 + textarea.id = "textarea1" 225 + textarea.value = "original" 226 + parent.appendChild(textarea) 227 227 228 - textarea.focus(); 228 + textarea.focus() 229 229 230 - const reference = document.createElement("div"); 231 - const refTextarea = document.createElement("textarea"); 232 - refTextarea.id = "textarea1"; 233 - refTextarea.value = "updated"; 234 - reference.appendChild(refTextarea); 230 + const reference = document.createElement("div") 231 + const refTextarea = document.createElement("textarea") 232 + refTextarea.id = "textarea1" 233 + refTextarea.value = "updated" 234 + reference.appendChild(refTextarea) 235 235 236 - morph(parent, reference, { ignoreActiveValue: true }); 236 + morph(parent, reference, { ignoreActiveValue: true }) 237 237 238 - expect(textarea.value).toBe("original"); 239 - }); 240 - }); 238 + expect(textarea.value).toBe("original") 239 + }) 240 + }) 241 241 242 242 describe("Property updates", () => { 243 243 it("should update option selected property", () => { 244 - const select = document.createElement("select"); 245 - const option1 = document.createElement("option"); 246 - option1.value = "1"; 247 - option1.textContent = "Option 1"; 248 - const option2 = document.createElement("option"); 249 - option2.value = "2"; 250 - option2.textContent = "Option 2"; 251 - select.appendChild(option1); 252 - select.appendChild(option2); 244 + const select = document.createElement("select") 245 + const option1 = document.createElement("option") 246 + option1.value = "1" 247 + option1.textContent = "Option 1" 248 + const option2 = document.createElement("option") 249 + option2.value = "2" 250 + option2.textContent = "Option 2" 251 + select.appendChild(option1) 252 + select.appendChild(option2) 253 253 254 - const refSelect = document.createElement("select"); 255 - const refOption1 = document.createElement("option"); 256 - refOption1.value = "1"; 257 - refOption1.textContent = "Option 1"; 258 - const refOption2 = document.createElement("option"); 259 - refOption2.value = "2"; 260 - refOption2.textContent = "Option 2"; 261 - refOption2.selected = true; 262 - refSelect.appendChild(refOption1); 263 - refSelect.appendChild(refOption2); 254 + const refSelect = document.createElement("select") 255 + const refOption1 = document.createElement("option") 256 + refOption1.value = "1" 257 + refOption1.textContent = "Option 1" 258 + const refOption2 = document.createElement("option") 259 + refOption2.value = "2" 260 + refOption2.textContent = "Option 2" 261 + refOption2.selected = true 262 + refSelect.appendChild(refOption1) 263 + refSelect.appendChild(refOption2) 264 264 265 - morph(select, refSelect); 265 + morph(select, refSelect) 266 266 267 - expect(option2.selected).toBe(true); 268 - }); 267 + expect(option2.selected).toBe(true) 268 + }) 269 269 270 270 it("should update textarea value with firstElementChild", () => { 271 - const parent = document.createElement("div"); 272 - const textarea = document.createElement("textarea"); 273 - textarea.name = "myTextarea"; 274 - textarea.value = "original"; 275 - textarea.defaultValue = "original"; 276 - const textContent = document.createElement("span"); 277 - textContent.textContent = "original"; 278 - textarea.appendChild(textContent); 279 - parent.appendChild(textarea); 271 + const parent = document.createElement("div") 272 + const textarea = document.createElement("textarea") 273 + textarea.name = "myTextarea" 274 + textarea.value = "original" 275 + textarea.defaultValue = "original" 276 + const textContent = document.createElement("span") 277 + textContent.textContent = "original" 278 + textarea.appendChild(textContent) 279 + parent.appendChild(textarea) 280 280 281 - const reference = document.createElement("div"); 282 - const refTextarea = document.createElement("textarea"); 283 - refTextarea.name = "myTextarea"; 284 - refTextarea.value = "updated"; 285 - reference.appendChild(refTextarea); 281 + const reference = document.createElement("div") 282 + const refTextarea = document.createElement("textarea") 283 + refTextarea.name = "myTextarea" 284 + refTextarea.value = "updated" 285 + reference.appendChild(refTextarea) 286 286 287 - morph(parent, reference); 287 + morph(parent, reference) 288 288 289 - expect(textarea.value).toBe("updated"); 289 + expect(textarea.value).toBe("updated") 290 290 if (textarea.firstElementChild) { 291 - expect(textarea.firstElementChild.textContent).toBe("updated"); 291 + expect(textarea.firstElementChild.textContent).toBe("updated") 292 292 } 293 - }); 293 + }) 294 294 295 295 it("should preserve modified textarea value with preserveModifiedValues", () => { 296 - const parent = document.createElement("div"); 297 - const textarea = document.createElement("textarea"); 298 - textarea.name = "myTextarea"; 299 - textarea.defaultValue = "default"; 300 - textarea.value = "modified"; 301 - parent.appendChild(textarea); 296 + const parent = document.createElement("div") 297 + const textarea = document.createElement("textarea") 298 + textarea.name = "myTextarea" 299 + textarea.defaultValue = "default" 300 + textarea.value = "modified" 301 + parent.appendChild(textarea) 302 302 303 - const reference = document.createElement("div"); 304 - const refTextarea = document.createElement("textarea"); 305 - refTextarea.name = "myTextarea"; 306 - refTextarea.value = "new value"; 307 - reference.appendChild(refTextarea); 303 + const reference = document.createElement("div") 304 + const refTextarea = document.createElement("textarea") 305 + refTextarea.name = "myTextarea" 306 + refTextarea.value = "new value" 307 + reference.appendChild(refTextarea) 308 308 309 - morph(parent, reference, { preserveModifiedValues: true }); 309 + morph(parent, reference, { preserveModifiedValues: true }) 310 310 311 - expect(textarea.value).toBe("modified"); 312 - }); 311 + expect(textarea.value).toBe("modified") 312 + }) 313 313 314 314 it("should update input indeterminate property", () => { 315 - const parent = document.createElement("div"); 316 - const input = document.createElement("input"); 317 - input.type = "checkbox"; 318 - input.indeterminate = false; 319 - parent.appendChild(input); 315 + const parent = document.createElement("div") 316 + const input = document.createElement("input") 317 + input.type = "checkbox" 318 + input.indeterminate = false 319 + parent.appendChild(input) 320 320 321 - const reference = document.createElement("div"); 322 - const refInput = document.createElement("input"); 323 - refInput.type = "checkbox"; 324 - refInput.indeterminate = true; 325 - reference.appendChild(refInput); 321 + const reference = document.createElement("div") 322 + const refInput = document.createElement("input") 323 + refInput.type = "checkbox" 324 + refInput.indeterminate = true 325 + reference.appendChild(refInput) 326 326 327 - morph(parent, reference); 327 + morph(parent, reference) 328 328 329 - expect(input.indeterminate).toBe(true); 330 - }); 329 + expect(input.indeterminate).toBe(true) 330 + }) 331 331 332 332 it("should update input disabled property", () => { 333 - const parent = document.createElement("div"); 334 - const input = document.createElement("input"); 335 - input.disabled = false; 336 - parent.appendChild(input); 333 + const parent = document.createElement("div") 334 + const input = document.createElement("input") 335 + input.disabled = false 336 + parent.appendChild(input) 337 337 338 - const reference = document.createElement("div"); 339 - const refInput = document.createElement("input"); 340 - refInput.disabled = true; 341 - reference.appendChild(refInput); 338 + const reference = document.createElement("div") 339 + const refInput = document.createElement("input") 340 + refInput.disabled = true 341 + reference.appendChild(refInput) 342 342 343 - morph(parent, reference); 343 + morph(parent, reference) 344 344 345 - expect(input.disabled).toBe(true); 346 - }); 345 + expect(input.disabled).toBe(true) 346 + }) 347 347 348 348 it("should not update file input value", () => { 349 - const parent = document.createElement("div"); 350 - const input = document.createElement("input"); 351 - input.type = "file"; 352 - parent.appendChild(input); 349 + const parent = document.createElement("div") 350 + const input = document.createElement("input") 351 + input.type = "file" 352 + parent.appendChild(input) 353 353 354 - const reference = document.createElement("div"); 355 - const refInput = document.createElement("input"); 356 - refInput.type = "file"; 357 - reference.appendChild(refInput); 354 + const reference = document.createElement("div") 355 + const refInput = document.createElement("input") 356 + refInput.type = "file" 357 + reference.appendChild(refInput) 358 358 359 - morph(parent, reference); 359 + morph(parent, reference) 360 360 361 - expect(input.type).toBe("file"); 362 - }); 363 - }); 361 + expect(input.type).toBe("file") 362 + }) 363 + }) 364 364 365 365 describe("Head element special handling", () => { 366 366 it("should handle nested head elements in child morphing", () => { 367 - const parent = document.createElement("div"); 368 - const head = document.createElement("head"); 369 - const meta1 = document.createElement("meta"); 370 - meta1.setAttribute("name", "test"); 371 - meta1.setAttribute("content", "value"); 372 - head.appendChild(meta1); 373 - parent.appendChild(head); 367 + const parent = document.createElement("div") 368 + const head = document.createElement("head") 369 + const meta1 = document.createElement("meta") 370 + meta1.setAttribute("name", "test") 371 + meta1.setAttribute("content", "value") 372 + head.appendChild(meta1) 373 + parent.appendChild(head) 374 374 375 - const reference = document.createElement("div"); 376 - const refHead = document.createElement("head"); 377 - const refMeta = document.createElement("meta"); 378 - refMeta.setAttribute("name", "test"); 379 - refMeta.setAttribute("content", "updated"); 380 - refHead.appendChild(refMeta); 381 - reference.appendChild(refHead); 375 + const reference = document.createElement("div") 376 + const refHead = document.createElement("head") 377 + const refMeta = document.createElement("meta") 378 + refMeta.setAttribute("name", "test") 379 + refMeta.setAttribute("content", "updated") 380 + refHead.appendChild(refMeta) 381 + reference.appendChild(refHead) 382 382 383 - morph(parent, reference); 383 + morph(parent, reference) 384 384 385 - expect(parent.querySelector("head")).toBeTruthy(); 386 - }); 387 - }); 385 + expect(parent.querySelector("head")).toBeTruthy() 386 + }) 387 + }) 388 388 389 389 describe("Child element morphing edge cases", () => { 390 390 it("should handle ID matching with overlapping ID sets", () => { 391 - const parent = document.createElement("div"); 392 - const child1 = document.createElement("div"); 393 - child1.id = "child1"; 394 - const nested = document.createElement("span"); 395 - nested.id = "nested"; 396 - child1.appendChild(nested); 391 + const parent = document.createElement("div") 392 + const child1 = document.createElement("div") 393 + child1.id = "child1" 394 + const nested = document.createElement("span") 395 + nested.id = "nested" 396 + child1.appendChild(nested) 397 397 398 - const child2 = document.createElement("div"); 399 - child2.id = "child2"; 398 + const child2 = document.createElement("div") 399 + child2.id = "child2" 400 400 401 - parent.appendChild(child1); 402 - parent.appendChild(child2); 401 + parent.appendChild(child1) 402 + parent.appendChild(child2) 403 403 404 - const reference = document.createElement("div"); 405 - const refChild1 = document.createElement("div"); 406 - refChild1.id = "child1"; 407 - const refNested = document.createElement("span"); 408 - refNested.id = "different"; 409 - refChild1.appendChild(refNested); 404 + const reference = document.createElement("div") 405 + const refChild1 = document.createElement("div") 406 + refChild1.id = "child1" 407 + const refNested = document.createElement("span") 408 + refNested.id = "different" 409 + refChild1.appendChild(refNested) 410 410 411 - const refChild2 = document.createElement("div"); 412 - refChild2.id = "child2"; 411 + const refChild2 = document.createElement("div") 412 + refChild2.id = "child2" 413 413 414 - reference.appendChild(refChild1); 415 - reference.appendChild(refChild2); 414 + reference.appendChild(refChild1) 415 + reference.appendChild(refChild2) 416 416 417 - morph(parent, reference); 417 + morph(parent, reference) 418 418 419 - expect(parent.children[0].id).toBe("child1"); 420 - }); 419 + expect(parent.children[0].id).toBe("child1") 420 + }) 421 421 422 422 it("should insert new node when no match found and beforeNodeAdded returns true", () => { 423 - const parent = document.createElement("div"); 424 - const existing = document.createElement("div"); 425 - existing.id = "existing"; 426 - parent.appendChild(existing); 423 + const parent = document.createElement("div") 424 + const existing = document.createElement("div") 425 + existing.id = "existing" 426 + parent.appendChild(existing) 427 427 428 - const reference = document.createElement("div"); 429 - const refNew = document.createElement("div"); 430 - refNew.id = "new"; 431 - const refExisting = document.createElement("div"); 432 - refExisting.id = "existing"; 433 - reference.appendChild(refNew); 434 - reference.appendChild(refExisting); 428 + const reference = document.createElement("div") 429 + const refNew = document.createElement("div") 430 + refNew.id = "new" 431 + const refExisting = document.createElement("div") 432 + refExisting.id = "existing" 433 + reference.appendChild(refNew) 434 + reference.appendChild(refExisting) 435 435 436 - let addedNode: Node | null = null; 436 + let addedNode: Node | null = null 437 437 morph(parent, reference, { 438 438 beforeNodeAdded: (node) => { 439 - addedNode = node; 440 - return true; 439 + addedNode = node 440 + return true 441 441 }, 442 - }); 442 + }) 443 443 444 - expect(addedNode).toBeTruthy(); 445 - expect(parent.children[0].id).toBe("new"); 446 - }); 444 + expect(addedNode).toBeTruthy() 445 + expect(parent.children[0].id).toBe("new") 446 + }) 447 447 448 448 it("should not insert new node when beforeNodeAdded returns false", () => { 449 - const parent = document.createElement("div"); 450 - const existing = document.createElement("div"); 451 - existing.id = "existing"; 452 - existing.textContent = "original"; 453 - parent.appendChild(existing); 449 + const parent = document.createElement("div") 450 + const existing = document.createElement("div") 451 + existing.id = "existing" 452 + existing.textContent = "original" 453 + parent.appendChild(existing) 454 454 455 - const reference = document.createElement("div"); 456 - const refNew = document.createElement("span"); 457 - refNew.id = "new"; 458 - refNew.textContent = "new content"; 459 - const refExisting = document.createElement("div"); 460 - refExisting.id = "existing"; 461 - refExisting.textContent = "updated"; 462 - reference.appendChild(refNew); 463 - reference.appendChild(refExisting); 455 + const reference = document.createElement("div") 456 + const refNew = document.createElement("span") 457 + refNew.id = "new" 458 + refNew.textContent = "new content" 459 + const refExisting = document.createElement("div") 460 + refExisting.id = "existing" 461 + refExisting.textContent = "updated" 462 + reference.appendChild(refNew) 463 + reference.appendChild(refExisting) 464 464 465 - let addCallbackCalled = false; 465 + let addCallbackCalled = false 466 466 morph(parent, reference, { 467 467 beforeNodeAdded: () => { 468 - addCallbackCalled = true; 469 - return false; 468 + addCallbackCalled = true 469 + return false 470 470 }, 471 - }); 471 + }) 472 472 473 473 // beforeNodeAdded should have been called 474 - expect(addCallbackCalled).toBe(true); 474 + expect(addCallbackCalled).toBe(true) 475 475 // The existing div will be morphed to match reference 476 - expect(parent.children[0].tagName).toBe("DIV"); 477 - }); 476 + expect(parent.children[0].tagName).toBe("DIV") 477 + }) 478 478 479 479 it("should call afterNodeMorphed for child elements even when new node inserted", () => { 480 - const parent = document.createElement("div"); 481 - const child = document.createElement("div"); 482 - child.id = "child"; 483 - parent.appendChild(child); 480 + const parent = document.createElement("div") 481 + const child = document.createElement("div") 482 + child.id = "child" 483 + parent.appendChild(child) 484 484 485 - const reference = document.createElement("div"); 486 - const refChild = document.createElement("span"); 487 - refChild.id = "newChild"; 488 - reference.appendChild(refChild); 485 + const reference = document.createElement("div") 486 + const refChild = document.createElement("span") 487 + refChild.id = "newChild" 488 + reference.appendChild(refChild) 489 489 490 - let morphedCalled = false; 490 + let morphedCalled = false 491 491 morph(parent, reference, { 492 492 afterNodeMorphed: () => { 493 - morphedCalled = true; 493 + morphedCalled = true 494 494 }, 495 - }); 495 + }) 496 496 497 - expect(morphedCalled).toBe(true); 498 - }); 499 - }); 497 + expect(morphedCalled).toBe(true) 498 + }) 499 + }) 500 500 501 501 describe("Sensitivity-based insertBefore", () => { 502 502 it("should handle sensitivity reordering when previousNode is insertionPoint", () => { 503 - const parent = document.createElement("div"); 504 - container.appendChild(parent); 503 + const parent = document.createElement("div") 504 + container.appendChild(parent) 505 505 506 - const input1 = document.createElement("input"); 507 - input1.id = "input1"; 508 - input1.value = "test"; 509 - input1.defaultValue = ""; 506 + const input1 = document.createElement("input") 507 + input1.id = "input1" 508 + input1.value = "test" 509 + input1.defaultValue = "" 510 510 511 - const input2 = document.createElement("input"); 512 - input2.id = "input2"; 513 - input2.value = "test2"; 514 - input2.defaultValue = ""; 511 + const input2 = document.createElement("input") 512 + input2.id = "input2" 513 + input2.value = "test2" 514 + input2.defaultValue = "" 515 515 516 - parent.appendChild(input1); 517 - parent.appendChild(input2); 516 + parent.appendChild(input1) 517 + parent.appendChild(input2) 518 518 519 - const reference = document.createElement("div"); 520 - const refInput2 = document.createElement("input"); 521 - refInput2.id = "input2"; 522 - refInput2.value = "test2"; 519 + const reference = document.createElement("div") 520 + const refInput2 = document.createElement("input") 521 + refInput2.id = "input2" 522 + refInput2.value = "test2" 523 523 524 - const refInput1 = document.createElement("input"); 525 - refInput1.id = "input1"; 526 - refInput1.value = "test"; 524 + const refInput1 = document.createElement("input") 525 + refInput1.id = "input1" 526 + refInput1.value = "test" 527 527 528 - reference.appendChild(refInput2); 529 - reference.appendChild(refInput1); 528 + reference.appendChild(refInput2) 529 + reference.appendChild(refInput1) 530 530 531 - morph(parent, reference); 531 + morph(parent, reference) 532 532 533 - expect(parent.children[0].id).toBe("input2"); 534 - expect(parent.children[1].id).toBe("input1"); 535 - }); 533 + expect(parent.children[0].id).toBe("input2") 534 + expect(parent.children[1].id).toBe("input1") 535 + }) 536 536 537 537 it("should break sensitivity reordering loop when previousNodeSensitivity >= sensitivity", () => { 538 - const parent = document.createElement("div"); 539 - container.appendChild(parent); 538 + const parent = document.createElement("div") 539 + container.appendChild(parent) 540 540 541 541 // Create inputs with different sensitivity levels 542 - const input1 = document.createElement("input"); 543 - input1.id = "input1"; 544 - input1.value = "modified1"; 545 - input1.defaultValue = "default1"; 542 + const input1 = document.createElement("input") 543 + input1.id = "input1" 544 + input1.value = "modified1" 545 + input1.defaultValue = "default1" 546 546 547 - const input2 = document.createElement("input"); 548 - input2.id = "input2"; 549 - input2.value = "modified2"; 550 - input2.defaultValue = "default2"; 547 + const input2 = document.createElement("input") 548 + input2.id = "input2" 549 + input2.value = "modified2" 550 + input2.defaultValue = "default2" 551 551 552 - const input3 = document.createElement("input"); 553 - input3.id = "input3"; 554 - input3.value = "modified3"; 555 - input3.defaultValue = "default3"; 552 + const input3 = document.createElement("input") 553 + input3.id = "input3" 554 + input3.value = "modified3" 555 + input3.defaultValue = "default3" 556 556 557 - parent.appendChild(input1); 558 - parent.appendChild(input2); 559 - parent.appendChild(input3); 557 + parent.appendChild(input1) 558 + parent.appendChild(input2) 559 + parent.appendChild(input3) 560 560 561 - const reference = document.createElement("div"); 562 - const refInput3 = document.createElement("input"); 563 - refInput3.id = "input3"; 561 + const reference = document.createElement("div") 562 + const refInput3 = document.createElement("input") 563 + refInput3.id = "input3" 564 564 565 - const refInput1 = document.createElement("input"); 566 - refInput1.id = "input1"; 565 + const refInput1 = document.createElement("input") 566 + refInput1.id = "input1" 567 567 568 - const refInput2 = document.createElement("input"); 569 - refInput2.id = "input2"; 568 + const refInput2 = document.createElement("input") 569 + refInput2.id = "input2" 570 570 571 - reference.appendChild(refInput3); 572 - reference.appendChild(refInput1); 573 - reference.appendChild(refInput2); 571 + reference.appendChild(refInput3) 572 + reference.appendChild(refInput1) 573 + reference.appendChild(refInput2) 574 574 575 - morph(parent, reference); 575 + morph(parent, reference) 576 576 577 577 // Verify elements were reordered 578 - expect(parent.children.length).toBe(3); 579 - }); 578 + expect(parent.children.length).toBe(3) 579 + }) 580 580 581 581 it("should handle insertBefore when node is not an element", () => { 582 - const parent = document.createElement("div"); 583 - const text1 = document.createTextNode("First"); 584 - const text2 = document.createTextNode("Second"); 585 - parent.appendChild(text1); 586 - parent.appendChild(text2); 582 + const parent = document.createElement("div") 583 + const text1 = document.createTextNode("First") 584 + const text2 = document.createTextNode("Second") 585 + parent.appendChild(text1) 586 + parent.appendChild(text2) 587 587 588 - const reference = document.createElement("div"); 589 - const refText1 = document.createTextNode("First Updated"); 590 - const refText2 = document.createTextNode("Second"); 591 - reference.appendChild(refText1); 592 - reference.appendChild(refText2); 588 + const reference = document.createElement("div") 589 + const refText1 = document.createTextNode("First Updated") 590 + const refText2 = document.createTextNode("Second") 591 + reference.appendChild(refText1) 592 + reference.appendChild(refText2) 593 593 594 - morph(parent, reference); 594 + morph(parent, reference) 595 595 596 - expect(parent.textContent).toBe("First UpdatedSecond"); 597 - }); 596 + expect(parent.textContent).toBe("First UpdatedSecond") 597 + }) 598 598 599 599 it("should handle insertBefore with zero sensitivity", () => { 600 - const parent = document.createElement("div"); 601 - const div1 = document.createElement("div"); 602 - div1.id = "div1"; 603 - const div2 = document.createElement("div"); 604 - div2.id = "div2"; 600 + const parent = document.createElement("div") 601 + const div1 = document.createElement("div") 602 + div1.id = "div1" 603 + const div2 = document.createElement("div") 604 + div2.id = "div2" 605 605 606 - parent.appendChild(div1); 607 - parent.appendChild(div2); 606 + parent.appendChild(div1) 607 + parent.appendChild(div2) 608 608 609 - const reference = document.createElement("div"); 610 - const refDiv2 = document.createElement("div"); 611 - refDiv2.id = "div2"; 612 - const refDiv1 = document.createElement("div"); 613 - refDiv1.id = "div1"; 609 + const reference = document.createElement("div") 610 + const refDiv2 = document.createElement("div") 611 + refDiv2.id = "div2" 612 + const refDiv1 = document.createElement("div") 613 + refDiv1.id = "div1" 614 614 615 - reference.appendChild(refDiv2); 616 - reference.appendChild(refDiv1); 615 + reference.appendChild(refDiv2) 616 + reference.appendChild(refDiv1) 617 617 618 - morph(parent, reference); 618 + morph(parent, reference) 619 619 620 - expect(parent.children[0].id).toBe("div2"); 621 - expect(parent.children[1].id).toBe("div1"); 622 - }); 623 - }); 620 + expect(parent.children[0].id).toBe("div2") 621 + expect(parent.children[1].id).toBe("div1") 622 + }) 623 + }) 624 624 625 625 describe("Callback cancellation", () => { 626 626 it("should call beforeAttributeUpdated and cancel attribute removal when it returns false", () => { 627 - const div = document.createElement("div"); 628 - div.setAttribute("data-keep", "value"); 629 - div.setAttribute("data-remove", "value"); 627 + const div = document.createElement("div") 628 + div.setAttribute("data-keep", "value") 629 + div.setAttribute("data-remove", "value") 630 630 631 - const reference = document.createElement("div"); 632 - reference.setAttribute("data-keep", "value"); 631 + const reference = document.createElement("div") 632 + reference.setAttribute("data-keep", "value") 633 633 634 634 morph(div, reference, { 635 635 beforeAttributeUpdated: (element, name, value) => { 636 636 if (name === "data-remove" && value === null) { 637 - return false; // Cancel removal 637 + return false // Cancel removal 638 638 } 639 - return true; 639 + return true 640 640 }, 641 - }); 641 + }) 642 642 643 643 // Attribute should still be there because callback returned false 644 - expect(div.hasAttribute("data-remove")).toBe(true); 645 - }); 644 + expect(div.hasAttribute("data-remove")).toBe(true) 645 + }) 646 646 647 647 it("should call beforePropertyUpdated and cancel property update when it returns false", () => { 648 - const input = document.createElement("input"); 649 - input.checked = false; 648 + const input = document.createElement("input") 649 + input.checked = false 650 650 651 - const reference = document.createElement("input"); 652 - reference.checked = true; 651 + const reference = document.createElement("input") 652 + reference.checked = true 653 653 654 654 morph(input, reference, { 655 655 beforePropertyUpdated: (node, propertyName, newValue) => { 656 656 if (propertyName === "checked" && newValue === true) { 657 - return false; // Cancel update 657 + return false // Cancel update 658 658 } 659 - return true; 659 + return true 660 660 }, 661 - }); 661 + }) 662 662 663 663 // Property should not be updated because callback returned false 664 - expect(input.checked).toBe(false); 665 - }); 666 - }); 664 + expect(input.checked).toBe(false) 665 + }) 666 + }) 667 667 668 668 describe("Empty ID handling", () => { 669 669 it("should ignore elements with empty id attribute", () => { 670 - const parent = document.createElement("div"); 671 - const child1 = document.createElement("div"); 672 - child1.setAttribute("id", ""); // Empty ID 673 - child1.textContent = "First"; 670 + const parent = document.createElement("div") 671 + const child1 = document.createElement("div") 672 + child1.setAttribute("id", "") // Empty ID 673 + child1.textContent = "First" 674 674 675 - const child2 = document.createElement("div"); 676 - child2.id = "valid-id"; 677 - child2.textContent = "Second"; 675 + const child2 = document.createElement("div") 676 + child2.id = "valid-id" 677 + child2.textContent = "Second" 678 678 679 - parent.appendChild(child1); 680 - parent.appendChild(child2); 679 + parent.appendChild(child1) 680 + parent.appendChild(child2) 681 681 682 - const reference = document.createElement("div"); 683 - const refChild1 = document.createElement("div"); 684 - refChild1.setAttribute("id", ""); 685 - refChild1.textContent = "First Updated"; 682 + const reference = document.createElement("div") 683 + const refChild1 = document.createElement("div") 684 + refChild1.setAttribute("id", "") 685 + refChild1.textContent = "First Updated" 686 686 687 - const refChild2 = document.createElement("div"); 688 - refChild2.id = "valid-id"; 689 - refChild2.textContent = "Second Updated"; 687 + const refChild2 = document.createElement("div") 688 + refChild2.id = "valid-id" 689 + refChild2.textContent = "Second Updated" 690 690 691 - reference.appendChild(refChild1); 692 - reference.appendChild(refChild2); 691 + reference.appendChild(refChild1) 692 + reference.appendChild(refChild2) 693 693 694 - morph(parent, reference); 694 + morph(parent, reference) 695 695 696 - expect(child1.textContent).toBe("First Updated"); 697 - expect(child2.textContent).toBe("Second Updated"); 698 - }); 699 - }); 696 + expect(child1.textContent).toBe("First Updated") 697 + expect(child2.textContent).toBe("Second Updated") 698 + }) 699 + }) 700 700 701 701 describe("Complex morphing scenarios", () => { 702 702 it("should handle mixed content with sensitive and non-sensitive elements", () => { 703 - const parent = document.createElement("div"); 704 - container.appendChild(parent); 703 + const parent = document.createElement("div") 704 + container.appendChild(parent) 705 705 706 - const div = document.createElement("div"); 707 - div.id = "div1"; 706 + const div = document.createElement("div") 707 + div.id = "div1" 708 708 709 - const input = document.createElement("input"); 710 - input.id = "input1"; 711 - input.value = "test"; 712 - input.defaultValue = ""; 709 + const input = document.createElement("input") 710 + input.id = "input1" 711 + input.value = "test" 712 + input.defaultValue = "" 713 713 714 - const canvas = document.createElement("canvas"); 715 - canvas.id = "canvas1"; 714 + const canvas = document.createElement("canvas") 715 + canvas.id = "canvas1" 716 716 717 - parent.appendChild(div); 718 - parent.appendChild(input); 719 - parent.appendChild(canvas); 717 + parent.appendChild(div) 718 + parent.appendChild(input) 719 + parent.appendChild(canvas) 720 720 721 - const reference = document.createElement("div"); 721 + const reference = document.createElement("div") 722 722 723 - const refCanvas = document.createElement("canvas"); 724 - refCanvas.id = "canvas1"; 723 + const refCanvas = document.createElement("canvas") 724 + refCanvas.id = "canvas1" 725 725 726 - const refInput = document.createElement("input"); 727 - refInput.id = "input1"; 726 + const refInput = document.createElement("input") 727 + refInput.id = "input1" 728 728 729 - const refDiv = document.createElement("div"); 730 - refDiv.id = "div1"; 729 + const refDiv = document.createElement("div") 730 + refDiv.id = "div1" 731 731 732 - reference.appendChild(refCanvas); 733 - reference.appendChild(refInput); 734 - reference.appendChild(refDiv); 732 + reference.appendChild(refCanvas) 733 + reference.appendChild(refInput) 734 + reference.appendChild(refDiv) 735 735 736 - morph(parent, reference); 736 + morph(parent, reference) 737 737 738 - expect(parent.children.length).toBe(3); 739 - }); 738 + expect(parent.children.length).toBe(3) 739 + }) 740 740 741 741 it("should handle text node morph with ariaBusy (non-element)", () => { 742 742 // Test line 136 - else block() for non-element nodes 743 - const parent = document.createElement("div"); 744 - const textNode = document.createTextNode("Original"); 745 - parent.appendChild(textNode); 743 + const parent = document.createElement("div") 744 + const textNode = document.createTextNode("Original") 745 + parent.appendChild(textNode) 746 746 747 - const reference = document.createTextNode("Updated"); 747 + const reference = document.createTextNode("Updated") 748 748 749 - morph(textNode, reference); 749 + morph(textNode, reference) 750 750 751 - expect(textNode.nodeValue).toBe("Updated"); 752 - }); 751 + expect(textNode.nodeValue).toBe("Updated") 752 + }) 753 753 754 754 it("should handle media elements that are playing", () => { 755 755 // Test lines 159-163 - media sensitivity with playing state 756 - const parent = document.createElement("div"); 757 - container.appendChild(parent); 756 + const parent = document.createElement("div") 757 + container.appendChild(parent) 758 758 759 - const video = document.createElement("video"); 760 - video.id = "video1"; 759 + const video = document.createElement("video") 760 + video.id = "video1" 761 761 // Mock playing state 762 - Object.defineProperty(video, "ended", { value: false, writable: true }); 763 - Object.defineProperty(video, "paused", { value: false, writable: true }); 764 - Object.defineProperty(video, "currentTime", { value: 5.0, writable: true }); 765 - parent.appendChild(video); 762 + Object.defineProperty(video, "ended", { value: false, writable: true }) 763 + Object.defineProperty(video, "paused", { value: false, writable: true }) 764 + Object.defineProperty(video, "currentTime", { value: 5.0, writable: true }) 765 + parent.appendChild(video) 766 766 767 - const reference = document.createElement("div"); 768 - const refVideo = document.createElement("video"); 769 - refVideo.id = "video1"; 770 - reference.appendChild(refVideo); 767 + const reference = document.createElement("div") 768 + const refVideo = document.createElement("video") 769 + refVideo.id = "video1" 770 + reference.appendChild(refVideo) 771 771 772 - morph(parent, reference); 772 + morph(parent, reference) 773 773 774 - expect(parent.querySelector("video")).toBeTruthy(); 775 - }); 774 + expect(parent.querySelector("video")).toBeTruthy() 775 + }) 776 776 777 777 it("should match elements by overlapping ID sets", () => { 778 778 // Test lines 372-373 - matching by overlapping ID sets 779 - const parent = document.createElement("div"); 779 + const parent = document.createElement("div") 780 780 781 - const outer1 = document.createElement("div"); 782 - outer1.id = "outer1"; 783 - const inner1a = document.createElement("span"); 784 - inner1a.id = "inner1a"; 785 - const inner1b = document.createElement("span"); 786 - inner1b.id = "inner1b"; 787 - outer1.appendChild(inner1a); 788 - outer1.appendChild(inner1b); 781 + const outer1 = document.createElement("div") 782 + outer1.id = "outer1" 783 + const inner1a = document.createElement("span") 784 + inner1a.id = "inner1a" 785 + const inner1b = document.createElement("span") 786 + inner1b.id = "inner1b" 787 + outer1.appendChild(inner1a) 788 + outer1.appendChild(inner1b) 789 789 790 - const outer2 = document.createElement("div"); 791 - outer2.id = "outer2"; 792 - const inner2 = document.createElement("span"); 793 - inner2.id = "inner2"; 794 - outer2.appendChild(inner2); 790 + const outer2 = document.createElement("div") 791 + outer2.id = "outer2" 792 + const inner2 = document.createElement("span") 793 + inner2.id = "inner2" 794 + outer2.appendChild(inner2) 795 795 796 - parent.appendChild(outer1); 797 - parent.appendChild(outer2); 796 + parent.appendChild(outer1) 797 + parent.appendChild(outer2) 798 798 799 - const reference = document.createElement("div"); 799 + const reference = document.createElement("div") 800 800 801 801 // Reference wants outer1 to come second, but references an inner ID 802 - const refOuter2 = document.createElement("div"); 803 - refOuter2.id = "outer2"; 804 - const refInner2 = document.createElement("span"); 805 - refInner2.id = "inner2"; 806 - refOuter2.appendChild(refInner2); 802 + const refOuter2 = document.createElement("div") 803 + refOuter2.id = "outer2" 804 + const refInner2 = document.createElement("span") 805 + refInner2.id = "inner2" 806 + refOuter2.appendChild(refInner2) 807 807 808 - const refOuter1 = document.createElement("div"); 809 - refOuter1.id = "outer1"; 810 - const refInner1a = document.createElement("span"); 811 - refInner1a.id = "inner1a"; 812 - refOuter1.appendChild(refInner1a); 808 + const refOuter1 = document.createElement("div") 809 + refOuter1.id = "outer1" 810 + const refInner1a = document.createElement("span") 811 + refInner1a.id = "inner1a" 812 + refOuter1.appendChild(refInner1a) 813 813 814 - reference.appendChild(refOuter2); 815 - reference.appendChild(refOuter1); 814 + reference.appendChild(refOuter2) 815 + reference.appendChild(refOuter1) 816 816 817 - morph(parent, reference); 817 + morph(parent, reference) 818 818 819 - expect(parent.children[0].id).toBe("outer2"); 820 - }); 819 + expect(parent.children[0].id).toBe("outer2") 820 + }) 821 821 822 822 it("should add completely new element when no match found by tag or ID", () => { 823 823 // Test lines 386-389 - adding new node with callbacks 824 - const parent = document.createElement("div"); 825 - const existing = document.createElement("div"); 826 - existing.id = "existing"; 827 - parent.appendChild(existing); 824 + const parent = document.createElement("div") 825 + const existing = document.createElement("div") 826 + existing.id = "existing" 827 + parent.appendChild(existing) 828 828 829 - const reference = document.createElement("div"); 830 - const refNew = document.createElement("article"); 831 - refNew.id = "brand-new"; 832 - refNew.textContent = "New content"; 833 - const refExisting = document.createElement("div"); 834 - refExisting.id = "existing"; 835 - reference.appendChild(refNew); 836 - reference.appendChild(refExisting); 829 + const reference = document.createElement("div") 830 + const refNew = document.createElement("article") 831 + refNew.id = "brand-new" 832 + refNew.textContent = "New content" 833 + const refExisting = document.createElement("div") 834 + refExisting.id = "existing" 835 + reference.appendChild(refNew) 836 + reference.appendChild(refExisting) 837 837 838 - let addedNode: Node | null = null; 839 - let afterAddedCalled = false; 838 + let addedNode: Node | null = null 839 + let afterAddedCalled = false 840 840 morph(parent, reference, { 841 841 beforeNodeAdded: (node) => { 842 - addedNode = node; 843 - return true; 842 + addedNode = node 843 + return true 844 844 }, 845 845 afterNodeAdded: (node) => { 846 - afterAddedCalled = true; 846 + afterAddedCalled = true 847 847 }, 848 - }); 848 + }) 849 849 850 - expect(addedNode).toBeTruthy(); 851 - expect(afterAddedCalled).toBe(true); 852 - expect(parent.children[0].tagName).toBe("ARTICLE"); 853 - }); 850 + expect(addedNode).toBeTruthy() 851 + expect(afterAddedCalled).toBe(true) 852 + expect(parent.children[0].tagName).toBe("ARTICLE") 853 + }) 854 854 855 855 it("should continue sensitivity loop when reordering multiple nodes", () => { 856 856 // Test lines 426-429 - continuing the sensitivity reordering loop 857 - const parent = document.createElement("div"); 858 - container.appendChild(parent); 857 + const parent = document.createElement("div") 858 + container.appendChild(parent) 859 859 860 860 // Create a chain of inputs with modified values (high sensitivity) 861 - const input1 = document.createElement("input"); 862 - input1.id = "input1"; 863 - input1.value = "modified1"; 864 - input1.defaultValue = "default1"; 861 + const input1 = document.createElement("input") 862 + input1.id = "input1" 863 + input1.value = "modified1" 864 + input1.defaultValue = "default1" 865 865 866 - const input2 = document.createElement("input"); 867 - input2.id = "input2"; 868 - input2.value = "modified2"; 869 - input2.defaultValue = "default2"; 866 + const input2 = document.createElement("input") 867 + input2.id = "input2" 868 + input2.value = "modified2" 869 + input2.defaultValue = "default2" 870 870 871 - const input3 = document.createElement("input"); 872 - input3.id = "input3"; 873 - input3.value = "modified3"; 874 - input3.defaultValue = "default3"; 871 + const input3 = document.createElement("input") 872 + input3.id = "input3" 873 + input3.value = "modified3" 874 + input3.defaultValue = "default3" 875 875 876 - const div = document.createElement("div"); 877 - div.id = "div1"; 876 + const div = document.createElement("div") 877 + div.id = "div1" 878 878 879 - parent.appendChild(div); 880 - parent.appendChild(input1); 881 - parent.appendChild(input2); 882 - parent.appendChild(input3); 879 + parent.appendChild(div) 880 + parent.appendChild(input1) 881 + parent.appendChild(input2) 882 + parent.appendChild(input3) 883 883 884 884 // Reference wants inputs in different order 885 - const reference = document.createElement("div"); 885 + const reference = document.createElement("div") 886 886 887 - const refInput3 = document.createElement("input"); 888 - refInput3.id = "input3"; 887 + const refInput3 = document.createElement("input") 888 + refInput3.id = "input3" 889 889 890 - const refInput2 = document.createElement("input"); 891 - refInput2.id = "input2"; 890 + const refInput2 = document.createElement("input") 891 + refInput2.id = "input2" 892 892 893 - const refInput1 = document.createElement("input"); 894 - refInput1.id = "input1"; 893 + const refInput1 = document.createElement("input") 894 + refInput1.id = "input1" 895 895 896 - const refDiv = document.createElement("div"); 897 - refDiv.id = "div1"; 896 + const refDiv = document.createElement("div") 897 + refDiv.id = "div1" 898 898 899 - reference.appendChild(refInput3); 900 - reference.appendChild(refInput2); 901 - reference.appendChild(refInput1); 902 - reference.appendChild(refDiv); 899 + reference.appendChild(refInput3) 900 + reference.appendChild(refInput2) 901 + reference.appendChild(refInput1) 902 + reference.appendChild(refDiv) 903 903 904 - morph(parent, reference); 904 + morph(parent, reference) 905 905 906 906 // The inputs should be reordered 907 - expect(parent.children.length).toBe(4); 908 - }); 907 + expect(parent.children.length).toBe(4) 908 + }) 909 909 910 910 describe("DOMParser edge cases", () => { 911 911 it("should explore parser behavior to trigger line 74", () => { ··· 916 916 // The else branch on line 74 appears to be unreachable in normal usage 917 917 918 918 // Let's verify with actual morph call 919 - const parent = document.createElement("div"); 920 - const div = document.createElement("div"); 921 - div.textContent = "Original"; 922 - parent.appendChild(div); 919 + const parent = document.createElement("div") 920 + const div = document.createElement("div") 921 + div.textContent = "Original" 922 + parent.appendChild(div) 923 923 924 924 // This should work fine 925 - morph(div, "<span>Test</span>"); 926 - expect(parent.firstChild?.textContent).toBe("Test"); 927 - }); 928 - }); 925 + morph(div, "<span>Test</span>") 926 + expect(parent.firstChild?.textContent).toBe("Test") 927 + }) 928 + }) 929 929 930 930 describe("Additional edge cases for remaining coverage", () => { 931 931 it("should handle element matching with nested IDs and no direct ID match", () => { 932 932 // More specific test for lines 372-373 933 - const parent = document.createElement("div"); 933 + const parent = document.createElement("div") 934 934 935 - const container1 = document.createElement("section"); 936 - const child1a = document.createElement("div"); 937 - child1a.id = "shared-id-a"; 938 - const child1b = document.createElement("div"); 939 - child1b.id = "shared-id-b"; 940 - container1.appendChild(child1a); 941 - container1.appendChild(child1b); 935 + const container1 = document.createElement("section") 936 + const child1a = document.createElement("div") 937 + child1a.id = "shared-id-a" 938 + const child1b = document.createElement("div") 939 + child1b.id = "shared-id-b" 940 + container1.appendChild(child1a) 941 + container1.appendChild(child1b) 942 942 943 - const container2 = document.createElement("section"); 944 - const child2 = document.createElement("div"); 945 - child2.id = "other-id"; 946 - container2.appendChild(child2); 943 + const container2 = document.createElement("section") 944 + const child2 = document.createElement("div") 945 + child2.id = "other-id" 946 + container2.appendChild(child2) 947 947 948 - parent.appendChild(container1); 949 - parent.appendChild(container2); 948 + parent.appendChild(container1) 949 + parent.appendChild(container2) 950 950 951 - const reference = document.createElement("div"); 952 - const refContainer = document.createElement("section"); 953 - const refChild = document.createElement("div"); 954 - refChild.id = "shared-id-a"; 955 - refContainer.appendChild(refChild); 951 + const reference = document.createElement("div") 952 + const refContainer = document.createElement("section") 953 + const refChild = document.createElement("div") 954 + refChild.id = "shared-id-a" 955 + refContainer.appendChild(refChild) 956 956 957 - reference.appendChild(refContainer); 957 + reference.appendChild(refContainer) 958 958 959 - morph(parent, reference); 959 + morph(parent, reference) 960 960 961 - expect(parent.children.length).toBeGreaterThanOrEqual(1); 962 - }); 961 + expect(parent.children.length).toBeGreaterThanOrEqual(1) 962 + }) 963 963 964 964 it("should insert node before when no ID or tag match exists", () => { 965 965 // Test for lines 386-389 with different scenario 966 - const parent = document.createElement("div"); 967 - const oldChild = document.createElement("p"); 968 - oldChild.textContent = "Old"; 969 - parent.appendChild(oldChild); 966 + const parent = document.createElement("div") 967 + const oldChild = document.createElement("p") 968 + oldChild.textContent = "Old" 969 + parent.appendChild(oldChild) 970 970 971 - const reference = document.createElement("div"); 972 - const newChild = document.createElement("article"); 973 - newChild.textContent = "New"; 974 - reference.appendChild(newChild); 971 + const reference = document.createElement("div") 972 + const newChild = document.createElement("article") 973 + newChild.textContent = "New" 974 + reference.appendChild(newChild) 975 975 976 - let beforeAddCalled = false; 977 - let afterAddCalled = false; 976 + let beforeAddCalled = false 977 + let afterAddCalled = false 978 978 979 979 morph(parent, reference, { 980 980 beforeNodeAdded: (node) => { 981 - beforeAddCalled = true; 982 - return true; 981 + beforeAddCalled = true 982 + return true 983 983 }, 984 984 afterNodeAdded: (node) => { 985 - afterAddCalled = true; 985 + afterAddCalled = true 986 986 }, 987 - }); 987 + }) 988 988 989 - expect(beforeAddCalled).toBe(true); 990 - expect(afterAddCalled).toBe(true); 991 - }); 989 + expect(beforeAddCalled).toBe(true) 990 + expect(afterAddCalled).toBe(true) 991 + }) 992 992 993 993 it("should handle multiple previousNode reorderings in sensitivity loop", () => { 994 994 // Test for lines 426-429 with more complex scenario 995 - const parent = document.createElement("div"); 996 - container.appendChild(parent); 995 + const parent = document.createElement("div") 996 + container.appendChild(parent) 997 997 998 - const regularDiv = document.createElement("div"); 999 - regularDiv.id = "regular"; 998 + const regularDiv = document.createElement("div") 999 + regularDiv.id = "regular" 1000 1000 1001 - const sensitiveInput1 = document.createElement("input"); 1002 - sensitiveInput1.id = "sensitive1"; 1003 - sensitiveInput1.value = "changed"; 1004 - sensitiveInput1.defaultValue = "default"; 1001 + const sensitiveInput1 = document.createElement("input") 1002 + sensitiveInput1.id = "sensitive1" 1003 + sensitiveInput1.value = "changed" 1004 + sensitiveInput1.defaultValue = "default" 1005 1005 1006 - const sensitiveInput2 = document.createElement("input"); 1007 - sensitiveInput2.id = "sensitive2"; 1008 - sensitiveInput2.value = "changed2"; 1009 - sensitiveInput2.defaultValue = "default2"; 1006 + const sensitiveInput2 = document.createElement("input") 1007 + sensitiveInput2.id = "sensitive2" 1008 + sensitiveInput2.value = "changed2" 1009 + sensitiveInput2.defaultValue = "default2" 1010 1010 1011 - const sensitiveInput3 = document.createElement("input"); 1012 - sensitiveInput3.id = "sensitive3"; 1013 - sensitiveInput3.value = "changed3"; 1014 - sensitiveInput3.defaultValue = "default3"; 1011 + const sensitiveInput3 = document.createElement("input") 1012 + sensitiveInput3.id = "sensitive3" 1013 + sensitiveInput3.value = "changed3" 1014 + sensitiveInput3.defaultValue = "default3" 1015 1015 1016 - parent.appendChild(regularDiv); 1017 - parent.appendChild(sensitiveInput1); 1018 - parent.appendChild(sensitiveInput2); 1019 - parent.appendChild(sensitiveInput3); 1016 + parent.appendChild(regularDiv) 1017 + parent.appendChild(sensitiveInput1) 1018 + parent.appendChild(sensitiveInput2) 1019 + parent.appendChild(sensitiveInput3) 1020 1020 1021 - const reference = document.createElement("div"); 1021 + const reference = document.createElement("div") 1022 1022 1023 - const refInput3 = document.createElement("input"); 1024 - refInput3.id = "sensitive3"; 1023 + const refInput3 = document.createElement("input") 1024 + refInput3.id = "sensitive3" 1025 1025 1026 - const refInput2 = document.createElement("input"); 1027 - refInput2.id = "sensitive2"; 1026 + const refInput2 = document.createElement("input") 1027 + refInput2.id = "sensitive2" 1028 1028 1029 - const refInput1 = document.createElement("input"); 1030 - refInput1.id = "sensitive1"; 1029 + const refInput1 = document.createElement("input") 1030 + refInput1.id = "sensitive1" 1031 1031 1032 - const refDiv = document.createElement("div"); 1033 - refDiv.id = "regular"; 1032 + const refDiv = document.createElement("div") 1033 + refDiv.id = "regular" 1034 1034 1035 - reference.appendChild(refInput3); 1036 - reference.appendChild(refInput2); 1037 - reference.appendChild(refInput1); 1038 - reference.appendChild(refDiv); 1035 + reference.appendChild(refInput3) 1036 + reference.appendChild(refInput2) 1037 + reference.appendChild(refInput1) 1038 + reference.appendChild(refDiv) 1039 1039 1040 - morph(parent, reference); 1040 + morph(parent, reference) 1041 1041 1042 - expect(parent.children.length).toBe(4); 1043 - }); 1042 + expect(parent.children.length).toBe(4) 1043 + }) 1044 1044 1045 1045 it("should match by overlapping ID sets in sibling scan - lines 372-373", () => { 1046 1046 // Lines 372-373: Match element by overlapping ID sets when ID doesn't match 1047 1047 // This requires: currentNode has ID != reference.id, but has nested IDs that overlap 1048 - const parent = document.createElement("div"); 1048 + const parent = document.createElement("div") 1049 1049 1050 1050 // First child with nested IDs 1051 - const div1 = document.createElement("div"); 1052 - div1.id = "div1"; 1053 - const nested1 = document.createElement("span"); 1054 - nested1.id = "overlap-id"; 1055 - div1.appendChild(nested1); 1051 + const div1 = document.createElement("div") 1052 + div1.id = "div1" 1053 + const nested1 = document.createElement("span") 1054 + nested1.id = "overlap-id" 1055 + div1.appendChild(nested1) 1056 1056 1057 1057 // Second child that's a match by tag name 1058 - const div2 = document.createElement("div"); 1059 - div2.id = "div2"; 1058 + const div2 = document.createElement("div") 1059 + div2.id = "div2" 1060 1060 1061 - parent.appendChild(div1); 1062 - parent.appendChild(div2); 1061 + parent.appendChild(div1) 1062 + parent.appendChild(div2) 1063 1063 1064 1064 // Reference wants div2 first, but references the overlap-id 1065 - const reference = document.createElement("div"); 1066 - const refDiv = document.createElement("div"); 1067 - refDiv.id = "target"; 1068 - const refNested = document.createElement("span"); 1069 - refNested.id = "overlap-id"; // This ID exists nested in div1 1070 - refDiv.appendChild(refNested); 1071 - reference.appendChild(refDiv); 1065 + const reference = document.createElement("div") 1066 + const refDiv = document.createElement("div") 1067 + refDiv.id = "target" 1068 + const refNested = document.createElement("span") 1069 + refNested.id = "overlap-id" // This ID exists nested in div1 1070 + refDiv.appendChild(refNested) 1071 + reference.appendChild(refDiv) 1072 1072 1073 - morph(parent, reference); 1073 + morph(parent, reference) 1074 1074 1075 - expect(parent.children.length).toBeGreaterThanOrEqual(1); 1076 - }); 1075 + expect(parent.children.length).toBeGreaterThanOrEqual(1) 1076 + }) 1077 1077 1078 1078 it("should add new node when no tag match exists - lines 386-389", () => { 1079 1079 // Lines 386-389: No nextMatchByTagName, so add new node 1080 1080 // This requires the reference child has a tag that doesn't exist in current children 1081 - const parent = document.createElement("div"); 1082 - const p = document.createElement("p"); 1083 - p.textContent = "Paragraph"; 1084 - parent.appendChild(p); 1081 + const parent = document.createElement("div") 1082 + const p = document.createElement("p") 1083 + p.textContent = "Paragraph" 1084 + parent.appendChild(p) 1085 1085 1086 - const reference = document.createElement("div"); 1086 + const reference = document.createElement("div") 1087 1087 // Use article tag which doesn't exist in parent 1088 - const article = document.createElement("article"); 1089 - article.textContent = "Article"; 1090 - const refP = document.createElement("p"); 1091 - reference.appendChild(article); 1092 - reference.appendChild(refP); 1088 + const article = document.createElement("article") 1089 + article.textContent = "Article" 1090 + const refP = document.createElement("p") 1091 + reference.appendChild(article) 1092 + reference.appendChild(refP) 1093 1093 1094 - let addedNode: Node | null = null; 1094 + let addedNode: Node | null = null 1095 1095 morph(parent, reference, { 1096 1096 beforeNodeAdded: (node) => { 1097 - addedNode = node; 1098 - return true; 1097 + addedNode = node 1098 + return true 1099 1099 }, 1100 1100 afterNodeAdded: (node) => { 1101 1101 // Lines 388-389 1102 1102 }, 1103 - }); 1103 + }) 1104 1104 1105 - expect(addedNode).toBeTruthy(); 1106 - expect(parent.querySelector("article")).toBeTruthy(); 1107 - }); 1105 + expect(addedNode).toBeTruthy() 1106 + expect(parent.querySelector("article")).toBeTruthy() 1107 + }) 1108 1108 1109 1109 it("should trigger line 74 - unreachable error path in parseChildNodeFromString", () => { 1110 1110 // Line 74: else throw new Error("[Morphlex] The string was not a valid HTML node."); ··· 1114 1114 // So doc.childNodes.length is always 1 (the html element) 1115 1115 1116 1116 // All valid HTML strings will pass the check on line 72 1117 - const parent = document.createElement("div"); 1118 - const child = document.createElement("div"); 1119 - parent.appendChild(child); 1117 + const parent = document.createElement("div") 1118 + const child = document.createElement("div") 1119 + parent.appendChild(child) 1120 1120 1121 1121 // Even empty string parses to valid document structure 1122 - morph(child, "<p>Test</p>"); 1123 - expect(parent.querySelector("p")?.textContent).toBe("Test"); 1124 - }); 1122 + morph(child, "<p>Test</p>") 1123 + expect(parent.querySelector("p")?.textContent).toBe("Test") 1124 + }) 1125 1125 1126 1126 it("should continue sensitivity reordering loop - lines 426-429", () => { 1127 1127 // Lines 426-429: previousNode reordering continues until break condition 1128 - const parent = document.createElement("div"); 1129 - container.appendChild(parent); 1128 + const parent = document.createElement("div") 1129 + container.appendChild(parent) 1130 1130 1131 1131 // Create low sensitivity element 1132 - const lowSensDiv = document.createElement("div"); 1133 - lowSensDiv.id = "low"; 1132 + const lowSensDiv = document.createElement("div") 1133 + lowSensDiv.id = "low" 1134 1134 1135 1135 // Create multiple high sensitivity elements that will trigger reordering 1136 - const highSens1 = document.createElement("input"); 1137 - highSens1.id = "high1"; 1138 - highSens1.value = "modified"; 1139 - highSens1.defaultValue = "default"; 1136 + const highSens1 = document.createElement("input") 1137 + highSens1.id = "high1" 1138 + highSens1.value = "modified" 1139 + highSens1.defaultValue = "default" 1140 1140 1141 - const highSens2 = document.createElement("input"); 1142 - highSens2.id = "high2"; 1143 - highSens2.value = "modified"; 1144 - highSens2.defaultValue = "default"; 1141 + const highSens2 = document.createElement("input") 1142 + highSens2.id = "high2" 1143 + highSens2.value = "modified" 1144 + highSens2.defaultValue = "default" 1145 1145 1146 - const highSens3 = document.createElement("input"); 1147 - highSens3.id = "high3"; 1148 - highSens3.value = "modified"; 1149 - highSens3.defaultValue = "default"; 1146 + const highSens3 = document.createElement("input") 1147 + highSens3.id = "high3" 1148 + highSens3.value = "modified" 1149 + highSens3.defaultValue = "default" 1150 1150 1151 1151 // Low sensitivity first, then high sensitivity elements 1152 - parent.appendChild(lowSensDiv); 1153 - parent.appendChild(highSens1); 1154 - parent.appendChild(highSens2); 1155 - parent.appendChild(highSens3); 1152 + parent.appendChild(lowSensDiv) 1153 + parent.appendChild(highSens1) 1154 + parent.appendChild(highSens2) 1155 + parent.appendChild(highSens3) 1156 1156 1157 1157 // Reference wants high sensitivity elements first 1158 - const reference = document.createElement("div"); 1159 - const refHigh3 = document.createElement("input"); 1160 - refHigh3.id = "high3"; 1161 - const refHigh2 = document.createElement("input"); 1162 - refHigh2.id = "high2"; 1163 - const refHigh1 = document.createElement("input"); 1164 - refHigh1.id = "high1"; 1165 - const refLow = document.createElement("div"); 1166 - refLow.id = "low"; 1158 + const reference = document.createElement("div") 1159 + const refHigh3 = document.createElement("input") 1160 + refHigh3.id = "high3" 1161 + const refHigh2 = document.createElement("input") 1162 + refHigh2.id = "high2" 1163 + const refHigh1 = document.createElement("input") 1164 + refHigh1.id = "high1" 1165 + const refLow = document.createElement("div") 1166 + refLow.id = "low" 1167 1167 1168 - reference.appendChild(refHigh3); 1169 - reference.appendChild(refHigh2); 1170 - reference.appendChild(refHigh1); 1171 - reference.appendChild(refLow); 1168 + reference.appendChild(refHigh3) 1169 + reference.appendChild(refHigh2) 1170 + reference.appendChild(refHigh1) 1171 + reference.appendChild(refLow) 1172 1172 1173 - morph(parent, reference); 1173 + morph(parent, reference) 1174 1174 1175 1175 // Verify reordering happened 1176 - expect(parent.children.length).toBe(4); 1176 + expect(parent.children.length).toBe(4) 1177 1177 // The loop should have moved multiple previousNodes 1178 - }); 1178 + }) 1179 1179 1180 1180 it("should handle case where child exists but refChild doesn't in loop - lines 332-333", () => { 1181 1181 // Lines 332-333 are actually unreachable in the for loop 1182 1182 // because we iterate up to refChildNodes.length, so refChild will always exist 1183 1183 // The cleanup happens in the while loop below (lines 338-341) 1184 1184 // This test documents that lines 332-333 appear to be dead code 1185 - const parent = document.createElement("div"); 1186 - const child1 = document.createElement("span"); 1187 - child1.textContent = "Keep"; 1188 - const child2 = document.createElement("span"); 1189 - child2.textContent = "Remove via while loop"; 1190 - parent.appendChild(child1); 1191 - parent.appendChild(child2); 1185 + const parent = document.createElement("div") 1186 + const child1 = document.createElement("span") 1187 + child1.textContent = "Keep" 1188 + const child2 = document.createElement("span") 1189 + child2.textContent = "Remove via while loop" 1190 + parent.appendChild(child1) 1191 + parent.appendChild(child2) 1192 1192 1193 - const reference = document.createElement("div"); 1194 - const refChild = document.createElement("span"); 1195 - refChild.textContent = "Keep Updated"; 1196 - reference.appendChild(refChild); 1193 + const reference = document.createElement("div") 1194 + const refChild = document.createElement("span") 1195 + refChild.textContent = "Keep Updated" 1196 + reference.appendChild(refChild) 1197 1197 1198 - morph(parent, reference); 1198 + morph(parent, reference) 1199 1199 1200 - expect(parent.children.length).toBe(1); 1201 - }); 1200 + expect(parent.children.length).toBe(1) 1201 + }) 1202 1202 1203 1203 it("should add new node when no ID or tag match exists - lines 386-389", () => { 1204 1204 // Lines 386-389 require: no nextMatchByTagName AND beforeNodeAdded returns true 1205 1205 // This means the first child must not match by tag, and no sibling matches either 1206 - const parent = document.createElement("div"); 1206 + const parent = document.createElement("div") 1207 1207 // Use a tag that won't match 1208 - const article = document.createElement("article"); 1209 - article.id = "article1"; 1210 - article.textContent = "Article"; 1211 - parent.appendChild(article); 1208 + const article = document.createElement("article") 1209 + article.id = "article1" 1210 + article.textContent = "Article" 1211 + parent.appendChild(article) 1212 1212 1213 - const reference = document.createElement("div"); 1213 + const reference = document.createElement("div") 1214 1214 // First child is a section (different tag), and has no ID match in siblings 1215 - const section = document.createElement("section"); 1216 - section.id = "section1"; 1217 - section.textContent = "Section"; 1215 + const section = document.createElement("section") 1216 + section.id = "section1" 1217 + section.textContent = "Section" 1218 1218 // Second child to trigger morphChildElement for the article 1219 - const refArticle = document.createElement("article"); 1220 - refArticle.id = "article1"; 1221 - reference.appendChild(section); 1222 - reference.appendChild(refArticle); 1219 + const refArticle = document.createElement("article") 1220 + refArticle.id = "article1" 1221 + reference.appendChild(section) 1222 + reference.appendChild(refArticle) 1223 1223 1224 - let beforeCalled = false; 1225 - let afterCalled = false; 1224 + let beforeCalled = false 1225 + let afterCalled = false 1226 1226 1227 1227 morph(parent, reference, { 1228 1228 beforeNodeAdded: (node) => { 1229 - beforeCalled = true; 1230 - return true; // Line 387: insertBefore is called 1229 + beforeCalled = true 1230 + return true // Line 387: insertBefore is called 1231 1231 }, 1232 1232 afterNodeAdded: (node) => { 1233 - afterCalled = true; // Line 389 1233 + afterCalled = true // Line 389 1234 1234 }, 1235 - }); 1235 + }) 1236 1236 1237 - expect(beforeCalled).toBe(true); 1238 - expect(afterCalled).toBe(true); 1239 - }); 1237 + expect(beforeCalled).toBe(true) 1238 + expect(afterCalled).toBe(true) 1239 + }) 1240 1240 1241 1241 it("should continue while loop in sensitivity reordering - lines 426-429", () => { 1242 1242 // Lines 426-429: while loop continues, previousNode gets reassigned 1243 1243 // Need multiple low-sensitivity nodes before a high-sensitivity node 1244 - const parent = document.createElement("div"); 1245 - container.appendChild(parent); 1244 + const parent = document.createElement("div") 1245 + container.appendChild(parent) 1246 1246 1247 1247 // Multiple regular divs (low sensitivity) 1248 - const div1 = document.createElement("div"); 1249 - div1.id = "div1"; 1250 - const div2 = document.createElement("div"); 1251 - div2.id = "div2"; 1252 - const div3 = document.createElement("div"); 1253 - div3.id = "div3"; 1248 + const div1 = document.createElement("div") 1249 + div1.id = "div1" 1250 + const div2 = document.createElement("div") 1251 + div2.id = "div2" 1252 + const div3 = document.createElement("div") 1253 + div3.id = "div3" 1254 1254 1255 1255 // High sensitivity input at the end 1256 - const input = document.createElement("input"); 1257 - input.id = "input1"; 1258 - input.value = "modified"; 1259 - input.defaultValue = "default"; 1256 + const input = document.createElement("input") 1257 + input.id = "input1" 1258 + input.value = "modified" 1259 + input.defaultValue = "default" 1260 1260 1261 - parent.appendChild(div1); 1262 - parent.appendChild(div2); 1263 - parent.appendChild(div3); 1264 - parent.appendChild(input); 1261 + parent.appendChild(div1) 1262 + parent.appendChild(div2) 1263 + parent.appendChild(div3) 1264 + parent.appendChild(input) 1265 1265 1266 1266 // Reference wants input first - this will trigger insertBefore with sensitivity reordering 1267 - const reference = document.createElement("div"); 1268 - const refInput = document.createElement("input"); 1269 - refInput.id = "input1"; 1270 - const refDiv1 = document.createElement("div"); 1271 - refDiv1.id = "div1"; 1272 - const refDiv2 = document.createElement("div"); 1273 - refDiv2.id = "div2"; 1274 - const refDiv3 = document.createElement("div"); 1275 - refDiv3.id = "div3"; 1267 + const reference = document.createElement("div") 1268 + const refInput = document.createElement("input") 1269 + refInput.id = "input1" 1270 + const refDiv1 = document.createElement("div") 1271 + refDiv1.id = "div1" 1272 + const refDiv2 = document.createElement("div") 1273 + refDiv2.id = "div2" 1274 + const refDiv3 = document.createElement("div") 1275 + refDiv3.id = "div3" 1276 1276 1277 - reference.appendChild(refInput); 1278 - reference.appendChild(refDiv1); 1279 - reference.appendChild(refDiv2); 1280 - reference.appendChild(refDiv3); 1277 + reference.appendChild(refInput) 1278 + reference.appendChild(refDiv1) 1279 + reference.appendChild(refDiv2) 1280 + reference.appendChild(refDiv3) 1281 1281 1282 - morph(parent, reference); 1282 + morph(parent, reference) 1283 1283 1284 1284 // Input should be moved to front, with divs following 1285 - expect(parent.children[0].id).toBe("input1"); 1286 - }); 1285 + expect(parent.children[0].id).toBe("input1") 1286 + }) 1287 1287 1288 1288 describe("Exact uncovered line tests", () => { 1289 1289 it("should cancel morphing with beforeNodeMorphed returning false in morphChildElement - line 300", () => { 1290 1290 // Line 300: return early when beforeNodeMorphed returns false in morphChildElement 1291 - const parent = document.createElement("div"); 1292 - const child = document.createElement("div"); 1293 - child.id = "child"; 1294 - parent.appendChild(child); 1291 + const parent = document.createElement("div") 1292 + const child = document.createElement("div") 1293 + child.id = "child" 1294 + parent.appendChild(child) 1295 1295 1296 - const reference = document.createElement("div"); 1297 - const refChild = document.createElement("div"); 1298 - refChild.id = "child"; 1299 - refChild.textContent = "updated"; 1300 - reference.appendChild(refChild); 1296 + const reference = document.createElement("div") 1297 + const refChild = document.createElement("div") 1298 + refChild.id = "child" 1299 + refChild.textContent = "updated" 1300 + reference.appendChild(refChild) 1301 1301 1302 - let callbackInvoked = false; 1302 + let callbackInvoked = false 1303 1303 morph(parent, reference, { 1304 1304 beforeNodeMorphed: (node) => { 1305 1305 if (node === child) { 1306 - callbackInvoked = true; 1307 - return false; // This triggers line 300 return 1306 + callbackInvoked = true 1307 + return false // This triggers line 300 return 1308 1308 } 1309 - return true; 1309 + return true 1310 1310 }, 1311 - }); 1311 + }) 1312 1312 1313 - expect(callbackInvoked).toBe(true); 1313 + expect(callbackInvoked).toBe(true) 1314 1314 // Child should not be updated because callback returned false 1315 - expect(child.textContent).toBe(""); 1316 - }); 1315 + expect(child.textContent).toBe("") 1316 + }) 1317 1317 1318 1318 it("should add completely new element type with no matches - lines 386-389", () => { 1319 1319 // Lines 386-389: else branch where no nextMatchByTagName exists 1320 1320 // Need a reference child with a tag that doesn't exist anywhere in parent 1321 - const parent = document.createElement("div"); 1322 - const p = document.createElement("p"); 1323 - p.textContent = "paragraph"; 1324 - parent.appendChild(p); 1321 + const parent = document.createElement("div") 1322 + const p = document.createElement("p") 1323 + p.textContent = "paragraph" 1324 + parent.appendChild(p) 1325 1325 1326 - const reference = document.createElement("div"); 1326 + const reference = document.createElement("div") 1327 1327 // Use custom element or uncommon tag 1328 - const custom = document.createElement("custom-element"); 1329 - custom.textContent = "custom"; 1330 - const refP = document.createElement("p"); 1331 - reference.appendChild(custom); 1332 - reference.appendChild(refP); 1328 + const custom = document.createElement("custom-element") 1329 + custom.textContent = "custom" 1330 + const refP = document.createElement("p") 1331 + reference.appendChild(custom) 1332 + reference.appendChild(refP) 1333 1333 1334 - let beforeCalled = false; 1335 - let afterCalled = false; 1334 + let beforeCalled = false 1335 + let afterCalled = false 1336 1336 1337 1337 morph(parent, reference, { 1338 1338 beforeNodeAdded: (node) => { 1339 1339 if ((node as Element).tagName === "CUSTOM-ELEMENT") { 1340 - beforeCalled = true; 1341 - return true; // Line 387-388 1340 + beforeCalled = true 1341 + return true // Line 387-388 1342 1342 } 1343 - return true; 1343 + return true 1344 1344 }, 1345 1345 afterNodeAdded: (node) => { 1346 1346 if ((node as Element).tagName === "CUSTOM-ELEMENT") { 1347 - afterCalled = true; // Line 389 1347 + afterCalled = true // Line 389 1348 1348 } 1349 1349 }, 1350 - }); 1350 + }) 1351 1351 1352 - expect(beforeCalled).toBe(true); 1353 - expect(afterCalled).toBe(true); 1354 - }); 1352 + expect(beforeCalled).toBe(true) 1353 + expect(afterCalled).toBe(true) 1354 + }) 1355 1355 1356 1356 it("should reorder with sensitivity - moving multiple previous nodes - lines 426-429", () => { 1357 1357 // Lines 426-429: while loop continues moving previousNode 1358 - const parent = document.createElement("div"); 1359 - container.appendChild(parent); 1358 + const parent = document.createElement("div") 1359 + container.appendChild(parent) 1360 1360 1361 1361 // Create a scenario where multiple low-sensitivity nodes need to be moved past a high-sensitivity node 1362 - const div1 = document.createElement("div"); 1363 - div1.id = "div1"; 1364 - const div2 = document.createElement("div"); 1365 - div2.id = "div2"; 1362 + const div1 = document.createElement("div") 1363 + div1.id = "div1" 1364 + const div2 = document.createElement("div") 1365 + div2.id = "div2" 1366 1366 1367 1367 // High sensitivity input 1368 - const input = document.createElement("input"); 1369 - input.id = "input"; 1370 - input.value = "modified"; 1371 - input.defaultValue = "default"; 1368 + const input = document.createElement("input") 1369 + input.id = "input" 1370 + input.value = "modified" 1371 + input.defaultValue = "default" 1372 1372 1373 - parent.appendChild(div1); 1374 - parent.appendChild(div2); 1375 - parent.appendChild(input); 1373 + parent.appendChild(div1) 1374 + parent.appendChild(div2) 1375 + parent.appendChild(input) 1376 1376 1377 1377 // Reference wants input first - will trigger sensitivity reordering 1378 - const reference = document.createElement("div"); 1379 - const refInput = document.createElement("input"); 1380 - refInput.id = "input"; 1381 - const refDiv1 = document.createElement("div"); 1382 - refDiv1.id = "div1"; 1383 - const refDiv2 = document.createElement("div"); 1384 - refDiv2.id = "div2"; 1378 + const reference = document.createElement("div") 1379 + const refInput = document.createElement("input") 1380 + refInput.id = "input" 1381 + const refDiv1 = document.createElement("div") 1382 + refDiv1.id = "div1" 1383 + const refDiv2 = document.createElement("div") 1384 + refDiv2.id = "div2" 1385 1385 1386 - reference.appendChild(refInput); 1387 - reference.appendChild(refDiv1); 1388 - reference.appendChild(refDiv2); 1386 + reference.appendChild(refInput) 1387 + reference.appendChild(refDiv1) 1388 + reference.appendChild(refDiv2) 1389 1389 1390 - morph(parent, reference); 1390 + morph(parent, reference) 1391 1391 1392 1392 // Input should be first due to higher sensitivity 1393 - expect(parent.children[0].id).toBe("input"); 1394 - }); 1395 - }); 1396 - }); 1397 - }); 1398 - }); 1393 + expect(parent.children[0].id).toBe("input") 1394 + }) 1395 + }) 1396 + }) 1397 + }) 1398 + })
+259 -259
test/morphlex-loops.test.ts
··· 1 - import { describe, it, expect, beforeEach, afterEach } from "vitest"; 2 - import { morph } from "../src/morphlex"; 1 + import { describe, it, expect, beforeEach, afterEach } from "vitest" 2 + import { morph } from "../src/morphlex" 3 3 4 4 describe("Morphlex - Infinite Loop Bug Detection", () => { 5 - let container: HTMLElement; 5 + let container: HTMLElement 6 6 7 7 beforeEach(() => { 8 - container = document.createElement("div"); 9 - document.body.appendChild(container); 10 - }); 8 + container = document.createElement("div") 9 + document.body.appendChild(container) 10 + }) 11 11 12 12 afterEach(() => { 13 13 if (container && container.parentNode) { 14 - container.parentNode.removeChild(container); 14 + container.parentNode.removeChild(container) 15 15 } 16 - }); 16 + }) 17 17 18 18 describe("Sensitivity-based reordering", () => { 19 19 it("should not infinite loop when reordering sensitive elements", () => { 20 - const parent = document.createElement("div"); 20 + const parent = document.createElement("div") 21 21 22 22 // Create input (sensitive element) 23 - const input = document.createElement("input") as HTMLInputElement; 24 - input.id = "input1"; 25 - input.value = "test"; 23 + const input = document.createElement("input") as HTMLInputElement 24 + input.id = "input1" 25 + input.value = "test" 26 26 27 27 // Create regular div 28 - const div1 = document.createElement("div"); 29 - div1.id = "div1"; 30 - div1.textContent = "First"; 28 + const div1 = document.createElement("div") 29 + div1.id = "div1" 30 + div1.textContent = "First" 31 31 32 - const div2 = document.createElement("div"); 33 - div2.id = "div2"; 34 - div2.textContent = "Second"; 32 + const div2 = document.createElement("div") 33 + div2.id = "div2" 34 + div2.textContent = "Second" 35 35 36 - parent.appendChild(div1); 37 - parent.appendChild(input); 38 - parent.appendChild(div2); 36 + parent.appendChild(div1) 37 + parent.appendChild(input) 38 + parent.appendChild(div2) 39 39 40 40 // Reference wants to reorder them 41 - const reference = document.createElement("div"); 41 + const reference = document.createElement("div") 42 42 43 - const refDiv1 = document.createElement("div"); 44 - refDiv1.id = "div1"; 45 - refDiv1.textContent = "First"; 43 + const refDiv1 = document.createElement("div") 44 + refDiv1.id = "div1" 45 + refDiv1.textContent = "First" 46 46 47 - const refDiv2 = document.createElement("div"); 48 - refDiv2.id = "div2"; 49 - refDiv2.textContent = "Second"; 47 + const refDiv2 = document.createElement("div") 48 + refDiv2.id = "div2" 49 + refDiv2.textContent = "Second" 50 50 51 - const refInput = document.createElement("input") as HTMLInputElement; 52 - refInput.id = "input1"; 51 + const refInput = document.createElement("input") as HTMLInputElement 52 + refInput.id = "input1" 53 53 54 - reference.appendChild(refDiv1); 55 - reference.appendChild(refDiv2); 56 - reference.appendChild(refInput); 54 + reference.appendChild(refDiv1) 55 + reference.appendChild(refDiv2) 56 + reference.appendChild(refInput) 57 57 58 58 // This should complete without infinite loop 59 - const startTime = Date.now(); 60 - morph(parent, reference); 61 - const endTime = Date.now(); 59 + const startTime = Date.now() 60 + morph(parent, reference) 61 + const endTime = Date.now() 62 62 63 63 // Should complete in reasonable time (< 1 second) 64 - expect(endTime - startTime).toBeLessThan(1000); 65 - expect(parent.children.length).toBe(3); 66 - }); 64 + expect(endTime - startTime).toBeLessThan(1000) 65 + expect(parent.children.length).toBe(3) 66 + }) 67 67 68 68 it("should not infinite loop with multiple sensitive elements", () => { 69 - const parent = document.createElement("div"); 69 + const parent = document.createElement("div") 70 70 71 - const input1 = document.createElement("input") as HTMLInputElement; 72 - input1.id = "input1"; 71 + const input1 = document.createElement("input") as HTMLInputElement 72 + input1.id = "input1" 73 73 74 - const input2 = document.createElement("input") as HTMLInputElement; 75 - input2.id = "input2"; 74 + const input2 = document.createElement("input") as HTMLInputElement 75 + input2.id = "input2" 76 76 77 - const textarea = document.createElement("textarea"); 78 - textarea.id = "textarea1"; 77 + const textarea = document.createElement("textarea") 78 + textarea.id = "textarea1" 79 79 80 - parent.appendChild(input1); 81 - parent.appendChild(input2); 82 - parent.appendChild(textarea); 80 + parent.appendChild(input1) 81 + parent.appendChild(input2) 82 + parent.appendChild(textarea) 83 83 84 84 // Reverse order 85 - const reference = document.createElement("div"); 85 + const reference = document.createElement("div") 86 86 87 - const refTextarea = document.createElement("textarea"); 88 - refTextarea.id = "textarea1"; 87 + const refTextarea = document.createElement("textarea") 88 + refTextarea.id = "textarea1" 89 89 90 - const refInput2 = document.createElement("input") as HTMLInputElement; 91 - refInput2.id = "input2"; 90 + const refInput2 = document.createElement("input") as HTMLInputElement 91 + refInput2.id = "input2" 92 92 93 - const refInput1 = document.createElement("input") as HTMLInputElement; 94 - refInput1.id = "input1"; 93 + const refInput1 = document.createElement("input") as HTMLInputElement 94 + refInput1.id = "input1" 95 95 96 - reference.appendChild(refTextarea); 97 - reference.appendChild(refInput2); 98 - reference.appendChild(refInput1); 96 + reference.appendChild(refTextarea) 97 + reference.appendChild(refInput2) 98 + reference.appendChild(refInput1) 99 99 100 - const startTime = Date.now(); 101 - morph(parent, reference); 102 - const endTime = Date.now(); 100 + const startTime = Date.now() 101 + morph(parent, reference) 102 + const endTime = Date.now() 103 103 104 - expect(endTime - startTime).toBeLessThan(1000); 105 - expect(parent.children[0].id).toBe("textarea1"); 106 - expect(parent.children[1].id).toBe("input2"); 107 - expect(parent.children[2].id).toBe("input1"); 108 - }); 104 + expect(endTime - startTime).toBeLessThan(1000) 105 + expect(parent.children[0].id).toBe("textarea1") 106 + expect(parent.children[1].id).toBe("input2") 107 + expect(parent.children[2].id).toBe("input1") 108 + }) 109 109 110 110 it("should not infinite loop with modified input value", () => { 111 - const parent = document.createElement("div"); 111 + const parent = document.createElement("div") 112 112 113 - const input = document.createElement("input") as HTMLInputElement; 114 - input.id = "input1"; 115 - input.defaultValue = "default"; 116 - input.value = "modified"; 113 + const input = document.createElement("input") as HTMLInputElement 114 + input.id = "input1" 115 + input.defaultValue = "default" 116 + input.value = "modified" 117 117 118 - const div = document.createElement("div"); 119 - div.id = "div1"; 118 + const div = document.createElement("div") 119 + div.id = "div1" 120 120 121 - parent.appendChild(input); 122 - parent.appendChild(div); 121 + parent.appendChild(input) 122 + parent.appendChild(div) 123 123 124 - const reference = document.createElement("div"); 124 + const reference = document.createElement("div") 125 125 126 - const refDiv = document.createElement("div"); 127 - refDiv.id = "div1"; 126 + const refDiv = document.createElement("div") 127 + refDiv.id = "div1" 128 128 129 - const refInput = document.createElement("input") as HTMLInputElement; 130 - refInput.id = "input1"; 129 + const refInput = document.createElement("input") as HTMLInputElement 130 + refInput.id = "input1" 131 131 132 - reference.appendChild(refDiv); 133 - reference.appendChild(refInput); 132 + reference.appendChild(refDiv) 133 + reference.appendChild(refInput) 134 134 135 - const startTime = Date.now(); 136 - morph(parent, reference); 137 - const endTime = Date.now(); 135 + const startTime = Date.now() 136 + morph(parent, reference) 137 + const endTime = Date.now() 138 138 139 - expect(endTime - startTime).toBeLessThan(1000); 140 - }); 141 - }); 139 + expect(endTime - startTime).toBeLessThan(1000) 140 + }) 141 + }) 142 142 143 143 describe("ID-based matching loops", () => { 144 144 it("should not infinite loop when matching by overlapping ID sets", () => { 145 - const parent = document.createElement("div"); 145 + const parent = document.createElement("div") 146 146 147 - const outer1 = document.createElement("div"); 148 - outer1.id = "outer1"; 149 - const inner1 = document.createElement("span"); 150 - inner1.id = "inner1"; 151 - outer1.appendChild(inner1); 147 + const outer1 = document.createElement("div") 148 + outer1.id = "outer1" 149 + const inner1 = document.createElement("span") 150 + inner1.id = "inner1" 151 + outer1.appendChild(inner1) 152 152 153 - const outer2 = document.createElement("div"); 154 - outer2.id = "outer2"; 155 - const inner2 = document.createElement("span"); 156 - inner2.id = "inner2"; 157 - outer2.appendChild(inner2); 153 + const outer2 = document.createElement("div") 154 + outer2.id = "outer2" 155 + const inner2 = document.createElement("span") 156 + inner2.id = "inner2" 157 + outer2.appendChild(inner2) 158 158 159 - parent.appendChild(outer1); 160 - parent.appendChild(outer2); 159 + parent.appendChild(outer1) 160 + parent.appendChild(outer2) 161 161 162 162 // Reference has them in reverse order 163 - const reference = document.createElement("div"); 163 + const reference = document.createElement("div") 164 164 165 - const refOuter2 = document.createElement("div"); 166 - refOuter2.id = "outer2"; 167 - const refInner2 = document.createElement("span"); 168 - refInner2.id = "inner2"; 169 - refOuter2.appendChild(refInner2); 165 + const refOuter2 = document.createElement("div") 166 + refOuter2.id = "outer2" 167 + const refInner2 = document.createElement("span") 168 + refInner2.id = "inner2" 169 + refOuter2.appendChild(refInner2) 170 170 171 - const refOuter1 = document.createElement("div"); 172 - refOuter1.id = "outer1"; 173 - const refInner1 = document.createElement("span"); 174 - refInner1.id = "inner1"; 175 - refOuter1.appendChild(refInner1); 171 + const refOuter1 = document.createElement("div") 172 + refOuter1.id = "outer1" 173 + const refInner1 = document.createElement("span") 174 + refInner1.id = "inner1" 175 + refOuter1.appendChild(refInner1) 176 176 177 - reference.appendChild(refOuter2); 178 - reference.appendChild(refOuter1); 177 + reference.appendChild(refOuter2) 178 + reference.appendChild(refOuter1) 179 179 180 - const startTime = Date.now(); 181 - morph(parent, reference); 182 - const endTime = Date.now(); 180 + const startTime = Date.now() 181 + morph(parent, reference) 182 + const endTime = Date.now() 183 183 184 - expect(endTime - startTime).toBeLessThan(1000); 185 - expect(parent.children[0].id).toBe("outer2"); 186 - expect(parent.children[1].id).toBe("outer1"); 187 - }); 184 + expect(endTime - startTime).toBeLessThan(1000) 185 + expect(parent.children[0].id).toBe("outer2") 186 + expect(parent.children[1].id).toBe("outer1") 187 + }) 188 188 189 189 it("should not infinite loop when currentNode becomes child during matching", () => { 190 - const parent = document.createElement("div"); 190 + const parent = document.createElement("div") 191 191 192 - const child1 = document.createElement("div"); 193 - child1.id = "child1"; 192 + const child1 = document.createElement("div") 193 + child1.id = "child1" 194 194 195 - const child2 = document.createElement("div"); 196 - child2.id = "child2"; 195 + const child2 = document.createElement("div") 196 + child2.id = "child2" 197 197 198 - const child3 = document.createElement("div"); 199 - child3.id = "child3"; 198 + const child3 = document.createElement("div") 199 + child3.id = "child3" 200 200 201 - parent.appendChild(child1); 202 - parent.appendChild(child2); 203 - parent.appendChild(child3); 201 + parent.appendChild(child1) 202 + parent.appendChild(child2) 203 + parent.appendChild(child3) 204 204 205 - const reference = document.createElement("div"); 205 + const reference = document.createElement("div") 206 206 207 - const refChild2 = document.createElement("div"); 208 - refChild2.id = "child2"; 207 + const refChild2 = document.createElement("div") 208 + refChild2.id = "child2" 209 209 210 - const refChild3 = document.createElement("div"); 211 - refChild3.id = "child3"; 210 + const refChild3 = document.createElement("div") 211 + refChild3.id = "child3" 212 212 213 - const refChild1 = document.createElement("div"); 214 - refChild1.id = "child1"; 213 + const refChild1 = document.createElement("div") 214 + refChild1.id = "child1" 215 215 216 - reference.appendChild(refChild2); 217 - reference.appendChild(refChild3); 218 - reference.appendChild(refChild1); 216 + reference.appendChild(refChild2) 217 + reference.appendChild(refChild3) 218 + reference.appendChild(refChild1) 219 219 220 - const startTime = Date.now(); 221 - morph(parent, reference); 222 - const endTime = Date.now(); 220 + const startTime = Date.now() 221 + morph(parent, reference) 222 + const endTime = Date.now() 223 223 224 - expect(endTime - startTime).toBeLessThan(1000); 225 - }); 226 - }); 224 + expect(endTime - startTime).toBeLessThan(1000) 225 + }) 226 + }) 227 227 228 228 describe("Head element morphing loops", () => { 229 229 it("should not infinite loop when morphing head with many elements", () => { 230 - const originalHead = document.createElement("head"); 230 + const originalHead = document.createElement("head") 231 231 232 232 for (let i = 0; i < 10; i++) { 233 - const meta = document.createElement("meta"); 234 - meta.setAttribute("name", `meta-${i}`); 235 - meta.setAttribute("content", `value-${i}`); 236 - originalHead.appendChild(meta); 233 + const meta = document.createElement("meta") 234 + meta.setAttribute("name", `meta-${i}`) 235 + meta.setAttribute("content", `value-${i}`) 236 + originalHead.appendChild(meta) 237 237 } 238 238 239 - const referenceHead = document.createElement("head"); 239 + const referenceHead = document.createElement("head") 240 240 241 241 for (let i = 0; i < 10; i++) { 242 - const meta = document.createElement("meta"); 243 - meta.setAttribute("name", `meta-${i}`); 244 - meta.setAttribute("content", `updated-${i}`); 245 - referenceHead.appendChild(meta); 242 + const meta = document.createElement("meta") 243 + meta.setAttribute("name", `meta-${i}`) 244 + meta.setAttribute("content", `updated-${i}`) 245 + referenceHead.appendChild(meta) 246 246 } 247 247 248 - const startTime = Date.now(); 249 - morph(originalHead, referenceHead); 250 - const endTime = Date.now(); 248 + const startTime = Date.now() 249 + morph(originalHead, referenceHead) 250 + const endTime = Date.now() 251 251 252 - expect(endTime - startTime).toBeLessThan(1000); 253 - }); 252 + expect(endTime - startTime).toBeLessThan(1000) 253 + }) 254 254 255 255 it("should not infinite loop with identical outerHTML", () => { 256 - const originalHead = document.createElement("head"); 257 - const script1 = document.createElement("script"); 258 - script1.textContent = "console.log('test')"; 259 - originalHead.appendChild(script1); 256 + const originalHead = document.createElement("head") 257 + const script1 = document.createElement("script") 258 + script1.textContent = "console.log('test')" 259 + originalHead.appendChild(script1) 260 260 261 - const script2 = document.createElement("script"); 262 - script2.textContent = "console.log('test')"; 263 - originalHead.appendChild(script2); 261 + const script2 = document.createElement("script") 262 + script2.textContent = "console.log('test')" 263 + originalHead.appendChild(script2) 264 264 265 - const referenceHead = document.createElement("head"); 266 - const refScript = document.createElement("script"); 267 - refScript.textContent = "console.log('test')"; 268 - referenceHead.appendChild(refScript); 265 + const referenceHead = document.createElement("head") 266 + const refScript = document.createElement("script") 267 + refScript.textContent = "console.log('test')" 268 + referenceHead.appendChild(refScript) 269 269 270 - const startTime = Date.now(); 271 - morph(originalHead, referenceHead); 272 - const endTime = Date.now(); 270 + const startTime = Date.now() 271 + morph(originalHead, referenceHead) 272 + const endTime = Date.now() 273 273 274 - expect(endTime - startTime).toBeLessThan(1000); 275 - }); 276 - }); 274 + expect(endTime - startTime).toBeLessThan(1000) 275 + }) 276 + }) 277 277 278 278 describe("Recursive morphing loops", () => { 279 279 it("should not infinite loop with deeply nested structures", () => { 280 - const parent = document.createElement("div"); 281 - let current = parent; 280 + const parent = document.createElement("div") 281 + let current = parent 282 282 283 283 for (let i = 0; i < 20; i++) { 284 - const child = document.createElement("div"); 285 - child.id = `level-${i}`; 286 - current.appendChild(child); 287 - current = child; 284 + const child = document.createElement("div") 285 + child.id = `level-${i}` 286 + current.appendChild(child) 287 + current = child 288 288 } 289 289 290 - const reference = document.createElement("div"); 291 - let refCurrent = reference; 290 + const reference = document.createElement("div") 291 + let refCurrent = reference 292 292 293 293 for (let i = 0; i < 20; i++) { 294 - const child = document.createElement("div"); 295 - child.id = `level-${i}`; 296 - child.textContent = "updated"; 297 - refCurrent.appendChild(child); 298 - refCurrent = child; 294 + const child = document.createElement("div") 295 + child.id = `level-${i}` 296 + child.textContent = "updated" 297 + refCurrent.appendChild(child) 298 + refCurrent = child 299 299 } 300 300 301 - const startTime = Date.now(); 302 - morph(parent, reference); 303 - const endTime = Date.now(); 301 + const startTime = Date.now() 302 + morph(parent, reference) 303 + const endTime = Date.now() 304 304 305 - expect(endTime - startTime).toBeLessThan(2000); 306 - }); 305 + expect(endTime - startTime).toBeLessThan(2000) 306 + }) 307 307 308 308 it("should not infinite loop with circular-looking ID references", () => { 309 - const parent = document.createElement("div"); 309 + const parent = document.createElement("div") 310 310 311 - const a = document.createElement("div"); 312 - a.id = "a"; 313 - const b = document.createElement("div"); 314 - b.id = "b"; 315 - const c = document.createElement("div"); 316 - c.id = "c"; 311 + const a = document.createElement("div") 312 + a.id = "a" 313 + const b = document.createElement("div") 314 + b.id = "b" 315 + const c = document.createElement("div") 316 + c.id = "c" 317 317 318 - parent.appendChild(a); 319 - parent.appendChild(b); 320 - parent.appendChild(c); 318 + parent.appendChild(a) 319 + parent.appendChild(b) 320 + parent.appendChild(c) 321 321 322 - const reference = document.createElement("div"); 322 + const reference = document.createElement("div") 323 323 324 - const refB = document.createElement("div"); 325 - refB.id = "b"; 326 - const refC = document.createElement("div"); 327 - refC.id = "c"; 328 - const refA = document.createElement("div"); 329 - refA.id = "a"; 324 + const refB = document.createElement("div") 325 + refB.id = "b" 326 + const refC = document.createElement("div") 327 + refC.id = "c" 328 + const refA = document.createElement("div") 329 + refA.id = "a" 330 330 331 - reference.appendChild(refB); 332 - reference.appendChild(refC); 333 - reference.appendChild(refA); 331 + reference.appendChild(refB) 332 + reference.appendChild(refC) 333 + reference.appendChild(refA) 334 334 335 - const startTime = Date.now(); 336 - morph(parent, reference); 337 - const endTime = Date.now(); 335 + const startTime = Date.now() 336 + morph(parent, reference) 337 + const endTime = Date.now() 338 338 339 - expect(endTime - startTime).toBeLessThan(1000); 340 - expect(parent.children[0].id).toBe("b"); 341 - expect(parent.children[1].id).toBe("c"); 342 - expect(parent.children[2].id).toBe("a"); 343 - }); 344 - }); 339 + expect(endTime - startTime).toBeLessThan(1000) 340 + expect(parent.children[0].id).toBe("b") 341 + expect(parent.children[1].id).toBe("c") 342 + expect(parent.children[2].id).toBe("a") 343 + }) 344 + }) 345 345 346 346 describe("Edge case loops", () => { 347 347 it("should not infinite loop when node equals insertionPoint", () => { 348 - const parent = document.createElement("div"); 349 - const child = document.createElement("span"); 350 - child.textContent = "test"; 351 - parent.appendChild(child); 348 + const parent = document.createElement("div") 349 + const child = document.createElement("span") 350 + child.textContent = "test" 351 + parent.appendChild(child) 352 352 353 - const reference = document.createElement("div"); 354 - const refChild = document.createElement("span"); 355 - refChild.textContent = "test updated"; 356 - reference.appendChild(refChild); 353 + const reference = document.createElement("div") 354 + const refChild = document.createElement("span") 355 + refChild.textContent = "test updated" 356 + reference.appendChild(refChild) 357 357 358 - const startTime = Date.now(); 359 - morph(parent, reference); 360 - const endTime = Date.now(); 358 + const startTime = Date.now() 359 + morph(parent, reference) 360 + const endTime = Date.now() 361 361 362 - expect(endTime - startTime).toBeLessThan(1000); 363 - }); 362 + expect(endTime - startTime).toBeLessThan(1000) 363 + }) 364 364 365 365 it("should not infinite loop with empty elements", () => { 366 - const parent = document.createElement("div"); 367 - const reference = document.createElement("div"); 366 + const parent = document.createElement("div") 367 + const reference = document.createElement("div") 368 368 369 - const startTime = Date.now(); 370 - morph(parent, reference); 371 - const endTime = Date.now(); 369 + const startTime = Date.now() 370 + morph(parent, reference) 371 + const endTime = Date.now() 372 372 373 - expect(endTime - startTime).toBeLessThan(100); 374 - }); 373 + expect(endTime - startTime).toBeLessThan(100) 374 + }) 375 375 376 376 it("should not infinite loop when cleaning up excess nodes", () => { 377 - const parent = document.createElement("div"); 377 + const parent = document.createElement("div") 378 378 379 379 for (let i = 0; i < 100; i++) { 380 - const child = document.createElement("div"); 381 - parent.appendChild(child); 380 + const child = document.createElement("div") 381 + parent.appendChild(child) 382 382 } 383 383 384 - const reference = document.createElement("div"); 384 + const reference = document.createElement("div") 385 385 386 - const startTime = Date.now(); 387 - morph(parent, reference); 388 - const endTime = Date.now(); 386 + const startTime = Date.now() 387 + morph(parent, reference) 388 + const endTime = Date.now() 389 389 390 - expect(endTime - startTime).toBeLessThan(1000); 391 - expect(parent.children.length).toBe(0); 392 - }); 393 - }); 394 - }); 390 + expect(endTime - startTime).toBeLessThan(1000) 391 + expect(parent.children.length).toBe(0) 392 + }) 393 + }) 394 + })
+361 -361
test/morphlex.test.ts
··· 1 - import { describe, it, expect, beforeEach, afterEach } from "vitest"; 2 - import { morph, morphInner } from "../src/morphlex"; 1 + import { describe, it, expect, beforeEach, afterEach } from "vitest" 2 + import { morph, morphInner } from "../src/morphlex" 3 3 4 4 describe("Morphlex Vitest Suite", () => { 5 - let container: HTMLElement; 5 + let container: HTMLElement 6 6 7 7 beforeEach(() => { 8 - container = document.createElement("div"); 9 - document.body.appendChild(container); 10 - }); 8 + container = document.createElement("div") 9 + document.body.appendChild(container) 10 + }) 11 11 12 12 afterEach(() => { 13 13 if (container && container.parentNode) { 14 - container.parentNode.removeChild(container); 14 + container.parentNode.removeChild(container) 15 15 } 16 - }); 16 + }) 17 17 18 18 describe("morph() - Basic functionality", () => { 19 19 it("should update text content", () => { 20 - const original = document.createElement("div"); 21 - original.textContent = "Hello"; 20 + const original = document.createElement("div") 21 + original.textContent = "Hello" 22 22 23 - const reference = document.createElement("div"); 24 - reference.textContent = "World"; 23 + const reference = document.createElement("div") 24 + reference.textContent = "World" 25 25 26 - morph(original, reference); 26 + morph(original, reference) 27 27 28 - expect(original.textContent).toBe("World"); 29 - }); 28 + expect(original.textContent).toBe("World") 29 + }) 30 30 31 31 it("should accept HTML string as reference", () => { 32 - const original = document.createElement("div"); 33 - original.textContent = "Old"; 32 + const original = document.createElement("div") 33 + original.textContent = "Old" 34 34 35 - morph(original, "<div>New</div>"); 35 + morph(original, "<div>New</div>") 36 36 37 - expect(original.textContent).toBe("New"); 38 - }); 37 + expect(original.textContent).toBe("New") 38 + }) 39 39 40 40 it("should preserve element when morphing matching tags", () => { 41 - const original = document.createElement("div"); 42 - original.id = "test"; 43 - const elementRef = original; 41 + const original = document.createElement("div") 42 + original.id = "test" 43 + const elementRef = original 44 44 45 - const reference = document.createElement("div"); 46 - reference.textContent = "Updated"; 45 + const reference = document.createElement("div") 46 + reference.textContent = "Updated" 47 47 48 - morph(original, reference); 48 + morph(original, reference) 49 49 50 - expect(original).toBe(elementRef); 51 - expect(original.textContent).toBe("Updated"); 52 - }); 50 + expect(original).toBe(elementRef) 51 + expect(original.textContent).toBe("Updated") 52 + }) 53 53 54 54 it("should replace element when morphing different tags", () => { 55 - const original = document.createElement("div"); 56 - const parent = document.createElement("section"); 57 - parent.appendChild(original); 55 + const original = document.createElement("div") 56 + const parent = document.createElement("section") 57 + parent.appendChild(original) 58 58 59 - const reference = document.createElement("span"); 60 - reference.textContent = "Updated"; 59 + const reference = document.createElement("span") 60 + reference.textContent = "Updated" 61 61 62 - morph(original, reference); 62 + morph(original, reference) 63 63 64 - expect(parent.querySelector("span")).toBeTruthy(); 65 - expect(parent.querySelector("div")).toBeFalsy(); 66 - }); 67 - }); 64 + expect(parent.querySelector("span")).toBeTruthy() 65 + expect(parent.querySelector("div")).toBeFalsy() 66 + }) 67 + }) 68 68 69 69 describe("morph() - Attribute handling", () => { 70 70 it("should add attributes", () => { 71 - const original = document.createElement("button"); 71 + const original = document.createElement("button") 72 72 73 - const reference = document.createElement("button"); 74 - reference.setAttribute("class", "btn-primary"); 75 - reference.setAttribute("disabled", ""); 73 + const reference = document.createElement("button") 74 + reference.setAttribute("class", "btn-primary") 75 + reference.setAttribute("disabled", "") 76 76 77 - morph(original, reference); 77 + morph(original, reference) 78 78 79 - expect(original.className).toBe("btn-primary"); 80 - expect(original.hasAttribute("disabled")).toBe(true); 81 - }); 79 + expect(original.className).toBe("btn-primary") 80 + expect(original.hasAttribute("disabled")).toBe(true) 81 + }) 82 82 83 83 it("should remove attributes", () => { 84 - const original = document.createElement("div"); 85 - original.setAttribute("data-test", "value"); 84 + const original = document.createElement("div") 85 + original.setAttribute("data-test", "value") 86 86 87 - const reference = document.createElement("div"); 87 + const reference = document.createElement("div") 88 88 89 - morph(original, reference); 89 + morph(original, reference) 90 90 91 - expect(original.hasAttribute("data-test")).toBe(false); 92 - }); 91 + expect(original.hasAttribute("data-test")).toBe(false) 92 + }) 93 93 94 94 it("should update attributes", () => { 95 - const original = document.createElement("div"); 96 - original.setAttribute("data-value", "old"); 95 + const original = document.createElement("div") 96 + original.setAttribute("data-value", "old") 97 97 98 - const reference = document.createElement("div"); 99 - reference.setAttribute("data-value", "new"); 98 + const reference = document.createElement("div") 99 + reference.setAttribute("data-value", "new") 100 100 101 - morph(original, reference); 101 + morph(original, reference) 102 102 103 - expect(original.getAttribute("data-value")).toBe("new"); 104 - }); 103 + expect(original.getAttribute("data-value")).toBe("new") 104 + }) 105 105 106 106 it("should update class attribute", () => { 107 - const original = document.createElement("div"); 108 - original.className = "old-class"; 107 + const original = document.createElement("div") 108 + original.className = "old-class" 109 109 110 - const reference = document.createElement("div"); 111 - reference.className = "new-class"; 110 + const reference = document.createElement("div") 111 + reference.className = "new-class" 112 112 113 - morph(original, reference); 113 + morph(original, reference) 114 114 115 - expect(original.className).toBe("new-class"); 116 - }); 117 - }); 115 + expect(original.className).toBe("new-class") 116 + }) 117 + }) 118 118 119 119 describe("morph() - Child elements", () => { 120 120 it("should add child elements", () => { 121 - const original = document.createElement("ul"); 121 + const original = document.createElement("ul") 122 122 123 - const reference = document.createElement("ul"); 124 - const li1 = document.createElement("li"); 125 - li1.textContent = "Item 1"; 126 - const li2 = document.createElement("li"); 127 - li2.textContent = "Item 2"; 128 - reference.appendChild(li1); 129 - reference.appendChild(li2); 123 + const reference = document.createElement("ul") 124 + const li1 = document.createElement("li") 125 + li1.textContent = "Item 1" 126 + const li2 = document.createElement("li") 127 + li2.textContent = "Item 2" 128 + reference.appendChild(li1) 129 + reference.appendChild(li2) 130 130 131 - morph(original, reference); 131 + morph(original, reference) 132 132 133 - expect(original.children.length).toBe(2); 134 - expect(original.children[0].textContent).toBe("Item 1"); 135 - }); 133 + expect(original.children.length).toBe(2) 134 + expect(original.children[0].textContent).toBe("Item 1") 135 + }) 136 136 137 137 it("should remove excess child elements", () => { 138 - const original = document.createElement("ul"); 139 - original.innerHTML = "<li>A</li><li>B</li><li>C</li>"; 138 + const original = document.createElement("ul") 139 + original.innerHTML = "<li>A</li><li>B</li><li>C</li>" 140 140 141 - const reference = document.createElement("ul"); 142 - reference.innerHTML = "<li>A</li>"; 141 + const reference = document.createElement("ul") 142 + reference.innerHTML = "<li>A</li>" 143 143 144 - morph(original, reference); 144 + morph(original, reference) 145 145 146 - expect(original.children.length).toBe(1); 147 - }); 146 + expect(original.children.length).toBe(1) 147 + }) 148 148 149 149 it("should morph existing child elements", () => { 150 - const original = document.createElement("div"); 151 - const child = document.createElement("span"); 152 - child.textContent = "old"; 153 - original.appendChild(child); 150 + const original = document.createElement("div") 151 + const child = document.createElement("span") 152 + child.textContent = "old" 153 + original.appendChild(child) 154 154 155 - const reference = document.createElement("div"); 156 - const refChild = document.createElement("span"); 157 - refChild.textContent = "new"; 158 - reference.appendChild(refChild); 155 + const reference = document.createElement("div") 156 + const refChild = document.createElement("span") 157 + refChild.textContent = "new" 158 + reference.appendChild(refChild) 159 159 160 - morph(original, reference); 160 + morph(original, reference) 161 161 162 - expect(original.children[0].textContent).toBe("new"); 163 - }); 162 + expect(original.children[0].textContent).toBe("new") 163 + }) 164 164 165 165 it("should handle text nodes", () => { 166 - const original = document.createElement("div"); 167 - original.appendChild(document.createTextNode("Hello")); 166 + const original = document.createElement("div") 167 + original.appendChild(document.createTextNode("Hello")) 168 168 169 - const reference = document.createElement("div"); 170 - reference.appendChild(document.createTextNode("World")); 169 + const reference = document.createElement("div") 170 + reference.appendChild(document.createTextNode("World")) 171 171 172 - morph(original, reference); 172 + morph(original, reference) 173 173 174 - expect(original.textContent).toBe("World"); 175 - }); 174 + expect(original.textContent).toBe("World") 175 + }) 176 176 177 177 it("should handle mixed text and element nodes", () => { 178 - const original = document.createElement("div"); 179 - original.appendChild(document.createTextNode("Start ")); 180 - const span = document.createElement("span"); 181 - span.textContent = "middle"; 182 - original.appendChild(span); 183 - original.appendChild(document.createTextNode(" end")); 178 + const original = document.createElement("div") 179 + original.appendChild(document.createTextNode("Start ")) 180 + const span = document.createElement("span") 181 + span.textContent = "middle" 182 + original.appendChild(span) 183 + original.appendChild(document.createTextNode(" end")) 184 184 185 - const reference = document.createElement("div"); 186 - reference.appendChild(document.createTextNode("Start ")); 187 - const refSpan = document.createElement("span"); 188 - refSpan.textContent = "updated"; 189 - reference.appendChild(refSpan); 190 - reference.appendChild(document.createTextNode(" end")); 185 + const reference = document.createElement("div") 186 + reference.appendChild(document.createTextNode("Start ")) 187 + const refSpan = document.createElement("span") 188 + refSpan.textContent = "updated" 189 + reference.appendChild(refSpan) 190 + reference.appendChild(document.createTextNode(" end")) 191 191 192 - morph(original, reference); 192 + morph(original, reference) 193 193 194 - expect(original.textContent).toBe("Start updated end"); 195 - }); 196 - }); 194 + expect(original.textContent).toBe("Start updated end") 195 + }) 196 + }) 197 197 198 198 describe("morph() - Element identity and IDs", () => { 199 199 it("should preserve element identity when using IDs", () => { 200 - const original = document.createElement("div"); 201 - original.innerHTML = '<p id="p1">Para 1</p><p id="p2">Para 2</p>'; 200 + const original = document.createElement("div") 201 + original.innerHTML = '<p id="p1">Para 1</p><p id="p2">Para 2</p>' 202 202 203 - const reference = document.createElement("div"); 204 - reference.innerHTML = '<p id="p2">Para 2</p><p id="p1">Para 1</p>'; 203 + const reference = document.createElement("div") 204 + reference.innerHTML = '<p id="p2">Para 2</p><p id="p1">Para 1</p>' 205 205 206 - const p1Original = original.querySelector("#p1"); 206 + const p1Original = original.querySelector("#p1") 207 207 208 - morph(original, reference); 208 + morph(original, reference) 209 209 210 - const p1After = original.querySelector("#p1"); 210 + const p1After = original.querySelector("#p1") 211 211 212 - expect(p1After).toBe(p1Original); 213 - }); 212 + expect(p1After).toBe(p1Original) 213 + }) 214 214 215 215 it("should reorder elements with IDs correctly", () => { 216 - const original = document.createElement("div"); 217 - original.innerHTML = '<span id="a">A</span><span id="b">B</span><span id="c">C</span>'; 216 + const original = document.createElement("div") 217 + original.innerHTML = '<span id="a">A</span><span id="b">B</span><span id="c">C</span>' 218 218 219 - const reference = document.createElement("div"); 220 - reference.innerHTML = '<span id="c">C</span><span id="a">A</span><span id="b">B</span>'; 219 + const reference = document.createElement("div") 220 + reference.innerHTML = '<span id="c">C</span><span id="a">A</span><span id="b">B</span>' 221 221 222 - const originalA = original.querySelector("#a"); 222 + const originalA = original.querySelector("#a") 223 223 224 - morph(original, reference); 224 + morph(original, reference) 225 225 226 - const newA = original.querySelector("#a"); 226 + const newA = original.querySelector("#a") 227 227 228 - expect(newA).toBe(originalA); 229 - expect(original.children[1]).toBe(newA); 230 - }); 231 - }); 228 + expect(newA).toBe(originalA) 229 + expect(original.children[1]).toBe(newA) 230 + }) 231 + }) 232 232 233 233 describe("morph() - Callbacks", () => { 234 234 it("should call beforeNodeMorphed and afterNodeMorphed", () => { 235 - const original = document.createElement("div"); 236 - original.textContent = "Before"; 235 + const original = document.createElement("div") 236 + original.textContent = "Before" 237 237 238 - const reference = document.createElement("div"); 239 - reference.textContent = "After"; 238 + const reference = document.createElement("div") 239 + reference.textContent = "After" 240 240 241 - let beforeCalled = false; 242 - let afterCalled = false; 241 + let beforeCalled = false 242 + let afterCalled = false 243 243 244 244 morph(original, reference, { 245 245 beforeNodeMorphed: () => { 246 - beforeCalled = true; 247 - return true; 246 + beforeCalled = true 247 + return true 248 248 }, 249 249 afterNodeMorphed: () => { 250 - afterCalled = true; 250 + afterCalled = true 251 251 }, 252 - }); 252 + }) 253 253 254 - expect(beforeCalled).toBe(true); 255 - expect(afterCalled).toBe(true); 256 - }); 254 + expect(beforeCalled).toBe(true) 255 + expect(afterCalled).toBe(true) 256 + }) 257 257 258 258 it("should cancel morphing if beforeNodeMorphed returns false", () => { 259 - const original = document.createElement("div"); 260 - original.textContent = "Original"; 259 + const original = document.createElement("div") 260 + original.textContent = "Original" 261 261 262 - const reference = document.createElement("div"); 263 - reference.textContent = "Reference"; 262 + const reference = document.createElement("div") 263 + reference.textContent = "Reference" 264 264 265 265 morph(original, reference, { 266 266 beforeNodeMorphed: () => false, 267 - }); 267 + }) 268 268 269 - expect(original.textContent).toBe("Original"); 270 - }); 269 + expect(original.textContent).toBe("Original") 270 + }) 271 271 272 272 it("should call beforeNodeAdded and afterNodeAdded", () => { 273 - const original = document.createElement("div"); 273 + const original = document.createElement("div") 274 274 275 - const reference = document.createElement("div"); 276 - const newChild = document.createElement("p"); 277 - newChild.textContent = "New"; 278 - reference.appendChild(newChild); 275 + const reference = document.createElement("div") 276 + const newChild = document.createElement("p") 277 + newChild.textContent = "New" 278 + reference.appendChild(newChild) 279 279 280 - let beforeAddCalled = false; 281 - let afterAddCalled = false; 280 + let beforeAddCalled = false 281 + let afterAddCalled = false 282 282 283 283 morph(original, reference, { 284 284 beforeNodeAdded: () => { 285 - beforeAddCalled = true; 286 - return true; 285 + beforeAddCalled = true 286 + return true 287 287 }, 288 288 afterNodeAdded: () => { 289 - afterAddCalled = true; 289 + afterAddCalled = true 290 290 }, 291 - }); 291 + }) 292 292 293 - expect(beforeAddCalled).toBe(true); 294 - expect(afterAddCalled).toBe(true); 295 - }); 293 + expect(beforeAddCalled).toBe(true) 294 + expect(afterAddCalled).toBe(true) 295 + }) 296 296 297 297 it("should call beforeNodeRemoved and afterNodeRemoved", () => { 298 - const original = document.createElement("div"); 299 - const child = document.createElement("p"); 300 - child.textContent = "To remove"; 301 - original.appendChild(child); 298 + const original = document.createElement("div") 299 + const child = document.createElement("p") 300 + child.textContent = "To remove" 301 + original.appendChild(child) 302 302 303 - const reference = document.createElement("div"); 303 + const reference = document.createElement("div") 304 304 305 - let beforeRemoveCalled = false; 306 - let afterRemoveCalled = false; 305 + let beforeRemoveCalled = false 306 + let afterRemoveCalled = false 307 307 308 308 morph(original, reference, { 309 309 beforeNodeRemoved: () => { 310 - beforeRemoveCalled = true; 311 - return true; 310 + beforeRemoveCalled = true 311 + return true 312 312 }, 313 313 afterNodeRemoved: () => { 314 - afterRemoveCalled = true; 314 + afterRemoveCalled = true 315 315 }, 316 - }); 316 + }) 317 317 318 - expect(beforeRemoveCalled).toBe(true); 319 - expect(afterRemoveCalled).toBe(true); 320 - }); 318 + expect(beforeRemoveCalled).toBe(true) 319 + expect(afterRemoveCalled).toBe(true) 320 + }) 321 321 322 322 it("should call attribute update callbacks", () => { 323 - const original = document.createElement("div"); 323 + const original = document.createElement("div") 324 324 325 - const reference = document.createElement("div"); 326 - reference.setAttribute("data-test", "value"); 325 + const reference = document.createElement("div") 326 + reference.setAttribute("data-test", "value") 327 327 328 - let callbackCalled = false; 328 + let callbackCalled = false 329 329 330 330 morph(original, reference, { 331 331 afterAttributeUpdated: (element, attrName) => { 332 332 if (attrName === "data-test") { 333 - callbackCalled = true; 333 + callbackCalled = true 334 334 } 335 335 }, 336 - }); 336 + }) 337 337 338 - expect(callbackCalled).toBe(true); 339 - }); 340 - }); 338 + expect(callbackCalled).toBe(true) 339 + }) 340 + }) 341 341 342 342 describe("morph() - Form elements", () => { 343 343 it("should update input value", () => { 344 - const original = document.createElement("input") as HTMLInputElement; 345 - original.type = "text"; 346 - original.value = "old"; 344 + const original = document.createElement("input") as HTMLInputElement 345 + original.type = "text" 346 + original.value = "old" 347 347 348 - const reference = document.createElement("input") as HTMLInputElement; 349 - reference.type = "text"; 350 - reference.value = "new"; 348 + const reference = document.createElement("input") as HTMLInputElement 349 + reference.type = "text" 350 + reference.value = "new" 351 351 352 - morph(original, reference); 352 + morph(original, reference) 353 353 354 - expect(original.value).toBe("new"); 355 - }); 354 + expect(original.value).toBe("new") 355 + }) 356 356 357 357 it("should update checkbox checked state", () => { 358 - const original = document.createElement("input") as HTMLInputElement; 359 - original.type = "checkbox"; 360 - original.checked = false; 358 + const original = document.createElement("input") as HTMLInputElement 359 + original.type = "checkbox" 360 + original.checked = false 361 361 362 - const reference = document.createElement("input") as HTMLInputElement; 363 - reference.type = "checkbox"; 364 - reference.checked = true; 362 + const reference = document.createElement("input") as HTMLInputElement 363 + reference.type = "checkbox" 364 + reference.checked = true 365 365 366 - morph(original, reference); 366 + morph(original, reference) 367 367 368 - expect(original.checked).toBe(true); 369 - }); 368 + expect(original.checked).toBe(true) 369 + }) 370 370 371 371 it("should update textarea value", () => { 372 - const original = document.createElement("textarea") as HTMLTextAreaElement; 373 - original.textContent = "old text"; 372 + const original = document.createElement("textarea") as HTMLTextAreaElement 373 + original.textContent = "old text" 374 374 375 - const reference = document.createElement("textarea") as HTMLTextAreaElement; 376 - reference.textContent = "new text"; 375 + const reference = document.createElement("textarea") as HTMLTextAreaElement 376 + reference.textContent = "new text" 377 377 378 - morph(original, reference); 378 + morph(original, reference) 379 379 380 - expect(original.textContent).toBe("new text"); 381 - }); 382 - }); 380 + expect(original.textContent).toBe("new text") 381 + }) 382 + }) 383 383 384 384 describe("morph() - Options", () => { 385 385 it("should preserve modified values with preserveModifiedValues option", () => { 386 - const original = document.createElement("input") as HTMLInputElement; 387 - original.value = "user-input"; 386 + const original = document.createElement("input") as HTMLInputElement 387 + original.value = "user-input" 388 388 389 - const reference = document.createElement("input") as HTMLInputElement; 390 - reference.value = "from-server"; 389 + const reference = document.createElement("input") as HTMLInputElement 390 + reference.value = "from-server" 391 391 392 - morph(original, reference, { preserveModifiedValues: true }); 392 + morph(original, reference, { preserveModifiedValues: true }) 393 393 394 - expect(original.value).toBe("user-input"); 395 - }); 394 + expect(original.value).toBe("user-input") 395 + }) 396 396 397 397 it("should ignore active value with ignoreActiveValue option", () => { 398 - const original = document.createElement("input") as HTMLInputElement; 399 - original.value = "active"; 398 + const original = document.createElement("input") as HTMLInputElement 399 + original.value = "active" 400 400 401 - const reference = document.createElement("input") as HTMLInputElement; 402 - reference.value = "inactive"; 401 + const reference = document.createElement("input") as HTMLInputElement 402 + reference.value = "inactive" 403 403 404 - morph(original, reference, { ignoreActiveValue: true }); 404 + morph(original, reference, { ignoreActiveValue: true }) 405 405 406 - expect(original).toBeDefined(); 407 - }); 408 - }); 406 + expect(original).toBeDefined() 407 + }) 408 + }) 409 409 410 410 describe("morphInner() - Basic functionality", () => { 411 411 it("should morph inner content only", () => { 412 - const original = document.createElement("div"); 413 - original.id = "container"; 414 - original.innerHTML = "<p>Old</p>"; 412 + const original = document.createElement("div") 413 + original.id = "container" 414 + original.innerHTML = "<p>Old</p>" 415 415 416 - const reference = document.createElement("div"); 417 - reference.innerHTML = "<p>New</p>"; 416 + const reference = document.createElement("div") 417 + reference.innerHTML = "<p>New</p>" 418 418 419 - morphInner(original, reference); 419 + morphInner(original, reference) 420 420 421 - expect(original.id).toBe("container"); 422 - expect(original.innerHTML).toBe("<p>New</p>"); 423 - }); 421 + expect(original.id).toBe("container") 422 + expect(original.innerHTML).toBe("<p>New</p>") 423 + }) 424 424 425 425 it("should accept string reference for morphInner", () => { 426 - const original = document.createElement("div"); 427 - original.innerHTML = "<span>Old</span>"; 426 + const original = document.createElement("div") 427 + original.innerHTML = "<span>Old</span>" 428 428 429 - const reference = document.createElement("div"); 430 - reference.innerHTML = "<span>New</span>"; 429 + const reference = document.createElement("div") 430 + reference.innerHTML = "<span>New</span>" 431 431 432 - morphInner(original, reference); 432 + morphInner(original, reference) 433 433 434 - expect(original.innerHTML).toBe("<span>New</span>"); 435 - }); 434 + expect(original.innerHTML).toBe("<span>New</span>") 435 + }) 436 436 437 437 it("should preserve outer element attributes with morphInner", () => { 438 - const original = document.createElement("div"); 439 - original.setAttribute("class", "container"); 440 - original.setAttribute("data-id", "123"); 441 - original.innerHTML = "<p>Old</p>"; 438 + const original = document.createElement("div") 439 + original.setAttribute("class", "container") 440 + original.setAttribute("data-id", "123") 441 + original.innerHTML = "<p>Old</p>" 442 442 443 - const reference = document.createElement("div"); 444 - reference.setAttribute("class", "different"); 445 - reference.innerHTML = "<p>New</p>"; 443 + const reference = document.createElement("div") 444 + reference.setAttribute("class", "different") 445 + reference.innerHTML = "<p>New</p>" 446 446 447 - morphInner(original, reference); 447 + morphInner(original, reference) 448 448 449 - expect(original.getAttribute("class")).toBe("container"); 450 - expect(original.getAttribute("data-id")).toBe("123"); 451 - expect(original.innerHTML).toBe("<p>New</p>"); 452 - }); 449 + expect(original.getAttribute("class")).toBe("container") 450 + expect(original.getAttribute("data-id")).toBe("123") 451 + expect(original.innerHTML).toBe("<p>New</p>") 452 + }) 453 453 454 454 it("should update multiple children with morphInner", () => { 455 - const original = document.createElement("ul"); 456 - original.innerHTML = "<li>Item 1</li><li>Item 2</li>"; 455 + const original = document.createElement("ul") 456 + original.innerHTML = "<li>Item 1</li><li>Item 2</li>" 457 457 458 - const reference = document.createElement("ul"); 459 - reference.innerHTML = "<li>Item A</li><li>Item B</li><li>Item C</li>"; 458 + const reference = document.createElement("ul") 459 + reference.innerHTML = "<li>Item A</li><li>Item B</li><li>Item C</li>" 460 460 461 - morphInner(original, reference); 461 + morphInner(original, reference) 462 462 463 - expect(original.children.length).toBe(3); 464 - expect(original.children[0].textContent).toBe("Item A"); 465 - expect(original.children[2].textContent).toBe("Item C"); 466 - }); 463 + expect(original.children.length).toBe(3) 464 + expect(original.children[0].textContent).toBe("Item A") 465 + expect(original.children[2].textContent).toBe("Item C") 466 + }) 467 467 468 468 it("should empty contents with morphInner when reference has no children", () => { 469 - const original = document.createElement("div"); 470 - original.innerHTML = "<span>Content</span><p>More</p>"; 469 + const original = document.createElement("div") 470 + original.innerHTML = "<span>Content</span><p>More</p>" 471 471 472 - const reference = document.createElement("div"); 472 + const reference = document.createElement("div") 473 473 474 - morphInner(original, reference); 474 + morphInner(original, reference) 475 475 476 - expect(original.children.length).toBe(0); 477 - }); 478 - }); 476 + expect(original.children.length).toBe(0) 477 + }) 478 + }) 479 479 480 480 describe("Edge cases and complex scenarios", () => { 481 481 it("should handle empty elements", () => { 482 - const original = document.createElement("div"); 483 - const reference = document.createElement("div"); 482 + const original = document.createElement("div") 483 + const reference = document.createElement("div") 484 484 485 - expect(() => morph(original, reference)).not.toThrow(); 486 - expect(original.children.length).toBe(0); 487 - }); 485 + expect(() => morph(original, reference)).not.toThrow() 486 + expect(original.children.length).toBe(0) 487 + }) 488 488 489 489 it("should handle deeply nested structures", () => { 490 - const original = document.createElement("div"); 491 - original.innerHTML = "<div><div><div><span>Deep</span></div></div></div>"; 490 + const original = document.createElement("div") 491 + original.innerHTML = "<div><div><div><span>Deep</span></div></div></div>" 492 492 493 - const reference = document.createElement("div"); 494 - reference.innerHTML = "<div><div><div><span>Updated</span></div></div></div>"; 493 + const reference = document.createElement("div") 494 + reference.innerHTML = "<div><div><div><span>Updated</span></div></div></div>" 495 495 496 - morph(original, reference); 496 + morph(original, reference) 497 497 498 - expect(original.querySelector("span")?.textContent).toBe("Updated"); 499 - }); 498 + expect(original.querySelector("span")?.textContent).toBe("Updated") 499 + }) 500 500 501 501 it("should handle special characters in text", () => { 502 - const original = document.createElement("div"); 503 - original.textContent = "Hello & goodbye"; 502 + const original = document.createElement("div") 503 + original.textContent = "Hello & goodbye" 504 504 505 - const reference = document.createElement("div"); 506 - reference.textContent = 'Special <> characters "test"'; 505 + const reference = document.createElement("div") 506 + reference.textContent = 'Special <> characters "test"' 507 507 508 - morph(original, reference); 508 + morph(original, reference) 509 509 510 - expect(original.textContent).toBe('Special <> characters "test"'); 511 - }); 510 + expect(original.textContent).toBe('Special <> characters "test"') 511 + }) 512 512 513 513 it("should handle multiple class names", () => { 514 - const original = document.createElement("div"); 515 - original.classList.add("class1", "class2", "class3"); 514 + const original = document.createElement("div") 515 + original.classList.add("class1", "class2", "class3") 516 516 517 - const reference = document.createElement("div"); 518 - reference.classList.add("class2", "class3", "class4"); 517 + const reference = document.createElement("div") 518 + reference.classList.add("class2", "class3", "class4") 519 519 520 - morph(original, reference); 520 + morph(original, reference) 521 521 522 - expect(original.classList.contains("class2")).toBe(true); 523 - expect(original.classList.contains("class3")).toBe(true); 524 - expect(original.classList.contains("class4")).toBe(true); 525 - expect(original.classList.contains("class1")).toBe(false); 526 - }); 522 + expect(original.classList.contains("class2")).toBe(true) 523 + expect(original.classList.contains("class3")).toBe(true) 524 + expect(original.classList.contains("class4")).toBe(true) 525 + expect(original.classList.contains("class1")).toBe(false) 526 + }) 527 527 528 528 it("should handle element replacement", () => { 529 - const original = document.createElement("div"); 530 - const span = document.createElement("span"); 531 - span.textContent = "Span"; 532 - original.appendChild(span); 529 + const original = document.createElement("div") 530 + const span = document.createElement("span") 531 + span.textContent = "Span" 532 + original.appendChild(span) 533 533 534 - const reference = document.createElement("div"); 535 - const p = document.createElement("p"); 536 - p.textContent = "Paragraph"; 537 - reference.appendChild(p); 534 + const reference = document.createElement("div") 535 + const p = document.createElement("p") 536 + p.textContent = "Paragraph" 537 + reference.appendChild(p) 538 538 539 - morph(original, reference); 539 + morph(original, reference) 540 540 541 - expect(original.children[0].nodeName).toBe("P"); 542 - expect(original.children[0].textContent).toBe("Paragraph"); 543 - }); 541 + expect(original.children[0].nodeName).toBe("P") 542 + expect(original.children[0].textContent).toBe("Paragraph") 543 + }) 544 544 545 545 it("should handle list updates with ID preservation", () => { 546 - const original = document.createElement("ul"); 547 - original.innerHTML = '<li id="item-1">Item 1</li><li id="item-2">Item 2</li><li id="item-3">Item 3</li>'; 546 + const original = document.createElement("ul") 547 + original.innerHTML = '<li id="item-1">Item 1</li><li id="item-2">Item 2</li><li id="item-3">Item 3</li>' 548 548 549 - const item2Ref = original.querySelector("#item-2"); 549 + const item2Ref = original.querySelector("#item-2") 550 550 551 - const reference = document.createElement("ul"); 551 + const reference = document.createElement("ul") 552 552 reference.innerHTML = 553 - '<li id="item-1">Item 1</li><li id="item-3">Item 3</li><li id="item-2">Item 2</li><li id="item-4">Item 4</li>'; 553 + '<li id="item-1">Item 1</li><li id="item-3">Item 3</li><li id="item-2">Item 2</li><li id="item-4">Item 4</li>' 554 554 555 - morph(original, reference); 555 + morph(original, reference) 556 556 557 - expect(original.querySelector("#item-2")).toBe(item2Ref); 558 - expect(original.children.length).toBe(4); 559 - }); 557 + expect(original.querySelector("#item-2")).toBe(item2Ref) 558 + expect(original.children.length).toBe(4) 559 + }) 560 560 561 561 it("should handle complex page-like structure", () => { 562 - const original = document.createElement("main"); 562 + const original = document.createElement("main") 563 563 original.innerHTML = ` 564 564 <header id="header"> 565 565 <h1>Title</h1> ··· 567 567 <article> 568 568 <p>Old paragraph</p> 569 569 </article> 570 - `; 570 + ` 571 571 572 - const reference = document.createElement("main"); 572 + const reference = document.createElement("main") 573 573 reference.innerHTML = ` 574 574 <header id="header"> 575 575 <h1>New Title</h1> ··· 578 578 <p>New paragraph</p> 579 579 <p>Another paragraph</p> 580 580 </article> 581 - `; 581 + ` 582 582 583 - const headerRef = original.querySelector("#header"); 583 + const headerRef = original.querySelector("#header") 584 584 585 - morph(original, reference); 585 + morph(original, reference) 586 586 587 - expect(original.querySelector("#header")).toBe(headerRef); 588 - expect(original.querySelector("h1")?.textContent).toBe("New Title"); 589 - expect(original.querySelectorAll("article p").length).toBe(2); 590 - }); 587 + expect(original.querySelector("#header")).toBe(headerRef) 588 + expect(original.querySelector("h1")?.textContent).toBe("New Title") 589 + expect(original.querySelectorAll("article p").length).toBe(2) 590 + }) 591 591 592 592 it("should handle nested element morphing with updates", () => { 593 - const original = document.createElement("div"); 594 - original.innerHTML = "<p>Old <span>content</span></p>"; 593 + const original = document.createElement("div") 594 + original.innerHTML = "<p>Old <span>content</span></p>" 595 595 596 - const reference = document.createElement("div"); 597 - reference.innerHTML = "<p>New <span>text</span></p>"; 596 + const reference = document.createElement("div") 597 + reference.innerHTML = "<p>New <span>text</span></p>" 598 598 599 - morph(original, reference); 599 + morph(original, reference) 600 600 601 - expect(original.innerHTML).toBe("<p>New <span>text</span></p>"); 602 - }); 601 + expect(original.innerHTML).toBe("<p>New <span>text</span></p>") 602 + }) 603 603 604 604 it("should preserve element reference through morph", () => { 605 - const original = document.createElement("div"); 606 - original.textContent = "Original"; 605 + const original = document.createElement("div") 606 + original.textContent = "Original" 607 607 608 - const reference = document.createElement("div"); 609 - reference.textContent = "Updated"; 608 + const reference = document.createElement("div") 609 + reference.textContent = "Updated" 610 610 611 - const originalRef = original; 612 - morph(original, reference); 611 + const originalRef = original 612 + morph(original, reference) 613 613 614 - expect(original).toBe(originalRef); 615 - expect(original.textContent).toBe("Updated"); 616 - }); 617 - }); 618 - }); 614 + expect(original).toBe(originalRef) 615 + expect(original.textContent).toBe("Updated") 616 + }) 617 + }) 618 + })
+2 -2
vitest.config.ts
··· 1 - import { defineConfig } from "vitest/config"; 1 + import { defineConfig } from "vitest/config" 2 2 3 3 export default defineConfig({ 4 4 test: { ··· 7 7 testTimeout: 10000, 8 8 hookTimeout: 10000, 9 9 }, 10 - }); 10 + })