@fiscozen/link
Advanced tools
| body, html { | ||
| margin:0; padding: 0; | ||
| height: 100%; | ||
| } | ||
| body { | ||
| font-family: Helvetica Neue, Helvetica, Arial; | ||
| font-size: 14px; | ||
| color:#333; | ||
| } | ||
| .small { font-size: 12px; } | ||
| *, *:after, *:before { | ||
| -webkit-box-sizing:border-box; | ||
| -moz-box-sizing:border-box; | ||
| box-sizing:border-box; | ||
| } | ||
| h1 { font-size: 20px; margin: 0;} | ||
| h2 { font-size: 14px; } | ||
| pre { | ||
| font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; | ||
| margin: 0; | ||
| padding: 0; | ||
| -moz-tab-size: 2; | ||
| -o-tab-size: 2; | ||
| tab-size: 2; | ||
| } | ||
| a { color:#0074D9; text-decoration:none; } | ||
| a:hover { text-decoration:underline; } | ||
| .strong { font-weight: bold; } | ||
| .space-top1 { padding: 10px 0 0 0; } | ||
| .pad2y { padding: 20px 0; } | ||
| .pad1y { padding: 10px 0; } | ||
| .pad2x { padding: 0 20px; } | ||
| .pad2 { padding: 20px; } | ||
| .pad1 { padding: 10px; } | ||
| .space-left2 { padding-left:55px; } | ||
| .space-right2 { padding-right:20px; } | ||
| .center { text-align:center; } | ||
| .clearfix { display:block; } | ||
| .clearfix:after { | ||
| content:''; | ||
| display:block; | ||
| height:0; | ||
| clear:both; | ||
| visibility:hidden; | ||
| } | ||
| .fl { float: left; } | ||
| @media only screen and (max-width:640px) { | ||
| .col3 { width:100%; max-width:100%; } | ||
| .hide-mobile { display:none!important; } | ||
| } | ||
| .quiet { | ||
| color: #7f7f7f; | ||
| color: rgba(0,0,0,0.5); | ||
| } | ||
| .quiet a { opacity: 0.7; } | ||
| .fraction { | ||
| font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; | ||
| font-size: 10px; | ||
| color: #555; | ||
| background: #E8E8E8; | ||
| padding: 4px 5px; | ||
| border-radius: 3px; | ||
| vertical-align: middle; | ||
| } | ||
| div.path a:link, div.path a:visited { color: #333; } | ||
| table.coverage { | ||
| border-collapse: collapse; | ||
| margin: 10px 0 0 0; | ||
| padding: 0; | ||
| } | ||
| table.coverage td { | ||
| margin: 0; | ||
| padding: 0; | ||
| vertical-align: top; | ||
| } | ||
| table.coverage td.line-count { | ||
| text-align: right; | ||
| padding: 0 5px 0 20px; | ||
| } | ||
| table.coverage td.line-coverage { | ||
| text-align: right; | ||
| padding-right: 10px; | ||
| min-width:20px; | ||
| } | ||
| table.coverage td span.cline-any { | ||
| display: inline-block; | ||
| padding: 0 5px; | ||
| width: 100%; | ||
| } | ||
| .missing-if-branch { | ||
| display: inline-block; | ||
| margin-right: 5px; | ||
| border-radius: 3px; | ||
| position: relative; | ||
| padding: 0 4px; | ||
| background: #333; | ||
| color: yellow; | ||
| } | ||
| .skip-if-branch { | ||
| display: none; | ||
| margin-right: 10px; | ||
| position: relative; | ||
| padding: 0 4px; | ||
| background: #ccc; | ||
| color: white; | ||
| } | ||
| .missing-if-branch .typ, .skip-if-branch .typ { | ||
| color: inherit !important; | ||
| } | ||
| .coverage-summary { | ||
| border-collapse: collapse; | ||
| width: 100%; | ||
| } | ||
| .coverage-summary tr { border-bottom: 1px solid #bbb; } | ||
| .keyline-all { border: 1px solid #ddd; } | ||
| .coverage-summary td, .coverage-summary th { padding: 10px; } | ||
| .coverage-summary tbody { border: 1px solid #bbb; } | ||
| .coverage-summary td { border-right: 1px solid #bbb; } | ||
| .coverage-summary td:last-child { border-right: none; } | ||
| .coverage-summary th { | ||
| text-align: left; | ||
| font-weight: normal; | ||
| white-space: nowrap; | ||
| } | ||
| .coverage-summary th.file { border-right: none !important; } | ||
| .coverage-summary th.pct { } | ||
| .coverage-summary th.pic, | ||
| .coverage-summary th.abs, | ||
| .coverage-summary td.pct, | ||
| .coverage-summary td.abs { text-align: right; } | ||
| .coverage-summary td.file { white-space: nowrap; } | ||
| .coverage-summary td.pic { min-width: 120px !important; } | ||
| .coverage-summary tfoot td { } | ||
| .coverage-summary .sorter { | ||
| height: 10px; | ||
| width: 7px; | ||
| display: inline-block; | ||
| margin-left: 0.5em; | ||
| background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; | ||
| } | ||
| .coverage-summary .sorted .sorter { | ||
| background-position: 0 -20px; | ||
| } | ||
| .coverage-summary .sorted-desc .sorter { | ||
| background-position: 0 -10px; | ||
| } | ||
| .status-line { height: 10px; } | ||
| /* yellow */ | ||
| .cbranch-no { background: yellow !important; color: #111; } | ||
| /* dark red */ | ||
| .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } | ||
| .low .chart { border:1px solid #C21F39 } | ||
| .highlighted, | ||
| .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ | ||
| background: #C21F39 !important; | ||
| } | ||
| /* medium red */ | ||
| .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } | ||
| /* light red */ | ||
| .low, .cline-no { background:#FCE1E5 } | ||
| /* light green */ | ||
| .high, .cline-yes { background:rgb(230,245,208) } | ||
| /* medium green */ | ||
| .cstat-yes { background:rgb(161,215,106) } | ||
| /* dark green */ | ||
| .status-line.high, .high .cover-fill { background:rgb(77,146,33) } | ||
| .high .chart { border:1px solid rgb(77,146,33) } | ||
| /* dark yellow (gold) */ | ||
| .status-line.medium, .medium .cover-fill { background: #f9cd0b; } | ||
| .medium .chart { border:1px solid #f9cd0b; } | ||
| /* light yellow */ | ||
| .medium { background: #fff4c2; } | ||
| .cstat-skip { background: #ddd; color: #111; } | ||
| .fstat-skip { background: #ddd; color: #111 !important; } | ||
| .cbranch-skip { background: #ddd !important; color: #111; } | ||
| span.cline-neutral { background: #eaeaea; } | ||
| .coverage-summary td.empty { | ||
| opacity: .5; | ||
| padding-top: 4px; | ||
| padding-bottom: 4px; | ||
| line-height: 1; | ||
| color: #888; | ||
| } | ||
| .cover-fill, .cover-empty { | ||
| display:inline-block; | ||
| height: 12px; | ||
| } | ||
| .chart { | ||
| line-height: 0; | ||
| } | ||
| .cover-empty { | ||
| background: white; | ||
| } | ||
| .cover-full { | ||
| border-right: none !important; | ||
| } | ||
| pre.prettyprint { | ||
| border: none !important; | ||
| padding: 0 !important; | ||
| margin: 0 !important; | ||
| } | ||
| .com { color: #999 !important; } | ||
| .ignore-none { color: #999; font-weight: normal; } | ||
| .wrapper { | ||
| min-height: 100%; | ||
| height: auto !important; | ||
| height: 100%; | ||
| margin: 0 auto -48px; | ||
| } | ||
| .footer, .push { | ||
| height: 48px; | ||
| } |
| /* eslint-disable */ | ||
| var jumpToCode = (function init() { | ||
| // Classes of code we would like to highlight in the file view | ||
| var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; | ||
| // Elements to highlight in the file listing view | ||
| var fileListingElements = ['td.pct.low']; | ||
| // We don't want to select elements that are direct descendants of another match | ||
| var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` | ||
| // Selecter that finds elements on the page to which we can jump | ||
| var selector = | ||
| fileListingElements.join(', ') + | ||
| ', ' + | ||
| notSelector + | ||
| missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` | ||
| // The NodeList of matching elements | ||
| var missingCoverageElements = document.querySelectorAll(selector); | ||
| var currentIndex; | ||
| function toggleClass(index) { | ||
| missingCoverageElements | ||
| .item(currentIndex) | ||
| .classList.remove('highlighted'); | ||
| missingCoverageElements.item(index).classList.add('highlighted'); | ||
| } | ||
| function makeCurrent(index) { | ||
| toggleClass(index); | ||
| currentIndex = index; | ||
| missingCoverageElements.item(index).scrollIntoView({ | ||
| behavior: 'smooth', | ||
| block: 'center', | ||
| inline: 'center' | ||
| }); | ||
| } | ||
| function goToPrevious() { | ||
| var nextIndex = 0; | ||
| if (typeof currentIndex !== 'number' || currentIndex === 0) { | ||
| nextIndex = missingCoverageElements.length - 1; | ||
| } else if (missingCoverageElements.length > 1) { | ||
| nextIndex = currentIndex - 1; | ||
| } | ||
| makeCurrent(nextIndex); | ||
| } | ||
| function goToNext() { | ||
| var nextIndex = 0; | ||
| if ( | ||
| typeof currentIndex === 'number' && | ||
| currentIndex < missingCoverageElements.length - 1 | ||
| ) { | ||
| nextIndex = currentIndex + 1; | ||
| } | ||
| makeCurrent(nextIndex); | ||
| } | ||
| return function jump(event) { | ||
| if ( | ||
| document.getElementById('fileSearch') === document.activeElement && | ||
| document.activeElement != null | ||
| ) { | ||
| // if we're currently focused on the search input, we don't want to navigate | ||
| return; | ||
| } | ||
| switch (event.which) { | ||
| case 78: // n | ||
| case 74: // j | ||
| goToNext(); | ||
| break; | ||
| case 66: // b | ||
| case 75: // k | ||
| case 80: // p | ||
| goToPrevious(); | ||
| break; | ||
| } | ||
| }; | ||
| })(); | ||
| window.addEventListener('keydown', jumpToCode); |
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <coverage generated="1762523195109" clover="3.2.0"> | ||
| <project timestamp="1762523195109" name="All files"> | ||
| <metrics statements="199" coveredstatements="198" conditionals="32" coveredconditionals="30" methods="6" coveredmethods="6" elements="237" coveredelements="234" complexity="0" loc="199" ncloc="199" packages="1" files="1" classes="1"/> | ||
| <file name="FzLink.vue" path="/Users/fiscozen/Workspace/design_system/packages/link/src/FzLink.vue"> | ||
| <metrics statements="199" coveredstatements="198" conditionals="32" coveredconditionals="30" methods="6" coveredmethods="6"/> | ||
| <line num="1" count="1" type="stmt"/> | ||
| <line num="2" count="1" type="stmt"/> | ||
| <line num="3" count="1" type="stmt"/> | ||
| <line num="4" count="1" type="stmt"/> | ||
| <line num="5" count="1" type="stmt"/> | ||
| <line num="6" count="1" type="stmt"/> | ||
| <line num="7" count="1" type="stmt"/> | ||
| <line num="8" count="1" type="stmt"/> | ||
| <line num="9" count="1" type="stmt"/> | ||
| <line num="10" count="1" type="stmt"/> | ||
| <line num="11" count="1" type="stmt"/> | ||
| <line num="12" count="1" type="stmt"/> | ||
| <line num="13" count="1" type="stmt"/> | ||
| <line num="14" count="1" type="stmt"/> | ||
| <line num="15" count="1" type="stmt"/> | ||
| <line num="16" count="1" type="stmt"/> | ||
| <line num="17" count="1" type="stmt"/> | ||
| <line num="18" count="1" type="stmt"/> | ||
| <line num="19" count="1" type="stmt"/> | ||
| <line num="20" count="1" type="stmt"/> | ||
| <line num="21" count="1" type="stmt"/> | ||
| <line num="22" count="1" type="stmt"/> | ||
| <line num="23" count="1" type="stmt"/> | ||
| <line num="24" count="1" type="stmt"/> | ||
| <line num="25" count="1" type="stmt"/> | ||
| <line num="26" count="1" type="stmt"/> | ||
| <line num="27" count="1" type="stmt"/> | ||
| <line num="28" count="1" type="stmt"/> | ||
| <line num="29" count="1" type="stmt"/> | ||
| <line num="30" count="1" type="stmt"/> | ||
| <line num="31" count="1" type="stmt"/> | ||
| <line num="32" count="1" type="stmt"/> | ||
| <line num="33" count="1" type="stmt"/> | ||
| <line num="34" count="1" type="stmt"/> | ||
| <line num="35" count="1" type="stmt"/> | ||
| <line num="36" count="1" type="stmt"/> | ||
| <line num="37" count="1" type="stmt"/> | ||
| <line num="38" count="1" type="stmt"/> | ||
| <line num="39" count="1" type="stmt"/> | ||
| <line num="40" count="1" type="stmt"/> | ||
| <line num="41" count="1" type="stmt"/> | ||
| <line num="42" count="1" type="stmt"/> | ||
| <line num="43" count="1" type="stmt"/> | ||
| <line num="44" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="45" count="37" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="46" count="1" type="stmt"/> | ||
| <line num="47" count="1" type="stmt"/> | ||
| <line num="48" count="1" type="stmt"/> | ||
| <line num="49" count="1" type="stmt"/> | ||
| <line num="50" count="1" type="stmt"/> | ||
| <line num="51" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="52" count="36" type="stmt"/> | ||
| <line num="53" count="37" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="54" count="1" type="stmt"/> | ||
| <line num="55" count="1" type="stmt"/> | ||
| <line num="56" count="1" type="stmt"/> | ||
| <line num="57" count="1" type="stmt"/> | ||
| <line num="58" count="1" type="stmt"/> | ||
| <line num="59" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="60" count="35" type="stmt"/> | ||
| <line num="61" count="35" type="stmt"/> | ||
| <line num="62" count="1" type="stmt"/> | ||
| <line num="63" count="1" type="stmt"/> | ||
| <line num="64" count="1" type="stmt"/> | ||
| <line num="65" count="1" type="stmt"/> | ||
| <line num="66" count="1" type="stmt"/> | ||
| <line num="67" count="1" type="stmt"/> | ||
| <line num="68" count="1" type="stmt"/> | ||
| <line num="69" count="1" type="stmt"/> | ||
| <line num="70" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="71" count="37" type="stmt"/> | ||
| <line num="72" count="37" type="stmt"/> | ||
| <line num="73" count="37" type="stmt"/> | ||
| <line num="74" count="37" type="stmt"/> | ||
| <line num="75" count="37" type="stmt"/> | ||
| <line num="76" count="37" type="stmt"/> | ||
| <line num="77" count="1" type="stmt"/> | ||
| <line num="78" count="1" type="stmt"/> | ||
| <line num="79" count="1" type="stmt"/> | ||
| <line num="80" count="1" type="stmt"/> | ||
| <line num="81" count="1" type="stmt"/> | ||
| <line num="82" count="1" type="stmt"/> | ||
| <line num="83" count="1" type="stmt"/> | ||
| <line num="84" count="1" type="stmt"/> | ||
| <line num="85" count="1" type="cond" truecount="2" falsecount="0"/> | ||
| <line num="86" count="1" type="cond" truecount="2" falsecount="0"/> | ||
| <line num="87" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="88" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="89" count="1" type="cond" truecount="2" falsecount="0"/> | ||
| <line num="90" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="91" count="1" type="stmt"/> | ||
| <line num="92" count="1" type="stmt"/> | ||
| <line num="93" count="1" type="stmt"/> | ||
| <line num="94" count="1" type="stmt"/> | ||
| <line num="95" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="96" count="29" type="stmt"/> | ||
| <line num="97" count="29" type="stmt"/> | ||
| <line num="98" count="29" type="stmt"/> | ||
| <line num="99" count="29" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="100" count="2" type="stmt"/> | ||
| <line num="101" count="2" type="stmt"/> | ||
| <line num="102" count="29" type="stmt"/> | ||
| <line num="103" count="29" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="104" count="24" type="stmt"/> | ||
| <line num="105" count="24" type="stmt"/> | ||
| <line num="106" count="29" type="stmt"/> | ||
| <line num="107" count="29" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="108" count="2" type="stmt"/> | ||
| <line num="109" count="2" type="stmt"/> | ||
| <line num="110" count="29" type="stmt"/> | ||
| <line num="111" count="29" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="112" count="1" type="stmt"/> | ||
| <line num="113" count="1" type="stmt"/> | ||
| <line num="114" count="29" type="stmt"/> | ||
| <line num="115" count="29" type="stmt"/> | ||
| <line num="116" count="29" type="stmt"/> | ||
| <line num="117" count="1" type="stmt"/> | ||
| <line num="118" count="1" type="stmt"/> | ||
| <line num="119" count="1" type="stmt"/> | ||
| <line num="120" count="1" type="stmt"/> | ||
| <line num="121" count="1" type="stmt"/> | ||
| <line num="122" count="1" type="stmt"/> | ||
| <line num="123" count="1" type="stmt"/> | ||
| <line num="124" count="1" type="stmt"/> | ||
| <line num="125" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="126" count="8" type="stmt"/> | ||
| <line num="127" count="8" type="stmt"/> | ||
| <line num="128" count="8" type="stmt"/> | ||
| <line num="129" count="8" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="130" count="6" type="stmt"/> | ||
| <line num="131" count="6" type="stmt"/> | ||
| <line num="132" count="6" type="stmt"/> | ||
| <line num="133" count="8" type="stmt"/> | ||
| <line num="134" count="8" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="135" count="2" type="stmt"/> | ||
| <line num="136" count="2" type="stmt"/> | ||
| <line num="137" count="2" type="stmt"/> | ||
| <line num="138" count="8" type="stmt"/> | ||
| <line num="139" count="8" type="stmt"/> | ||
| <line num="140" count="8" type="stmt"/> | ||
| <line num="141" count="1" type="stmt"/> | ||
| <line num="142" count="1" type="stmt"/> | ||
| <line num="143" count="1" type="stmt"/> | ||
| <line num="144" count="1" type="stmt"/> | ||
| <line num="145" count="1" type="stmt"/> | ||
| <line num="146" count="1" type="stmt"/> | ||
| <line num="147" count="1" type="stmt"/> | ||
| <line num="148" count="1" type="stmt"/> | ||
| <line num="149" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="150" count="9" type="stmt"/> | ||
| <line num="151" count="9" type="stmt"/> | ||
| <line num="152" count="9" type="stmt"/> | ||
| <line num="153" count="9" type="cond" truecount="0" falsecount="1"/> | ||
| <line num="154" count="0" type="stmt"/> | ||
| <line num="155" count="1" type="stmt"/> | ||
| <line num="156" count="1" type="stmt"/> | ||
| <line num="157" count="1" type="stmt"/> | ||
| <line num="158" count="1" type="stmt"/> | ||
| <line num="159" count="1" type="stmt"/> | ||
| <line num="160" count="1" type="stmt"/> | ||
| <line num="161" count="1" type="stmt"/> | ||
| <line num="162" count="1" type="stmt"/> | ||
| <line num="163" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="164" count="9" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="165" count="2" type="stmt"/> | ||
| <line num="166" count="2" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="167" count="7" type="stmt"/> | ||
| <line num="168" count="1" type="stmt"/> | ||
| <line num="169" count="1" type="stmt"/> | ||
| <line num="170" count="1" type="stmt"/> | ||
| <line num="171" count="1" type="stmt"/> | ||
| <line num="172" count="1" type="stmt"/> | ||
| <line num="173" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="174" count="8" type="stmt"/> | ||
| <line num="175" count="8" type="cond" truecount="0" falsecount="1"/> | ||
| <line num="176" count="8" type="stmt"/> | ||
| <line num="177" count="8" type="stmt"/> | ||
| <line num="178" count="8" type="stmt"/> | ||
| <line num="179" count="8" type="stmt"/> | ||
| <line num="180" count="1" type="stmt"/> | ||
| <line num="181" count="1" type="stmt"/> | ||
| <line num="182" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="183" count="9" type="stmt"/> | ||
| <line num="184" count="9" type="stmt"/> | ||
| <line num="185" count="9" type="stmt"/> | ||
| <line num="186" count="9" type="stmt"/> | ||
| <line num="187" count="9" type="stmt"/> | ||
| <line num="188" count="9" type="stmt"/> | ||
| <line num="189" count="1" type="stmt"/> | ||
| <line num="190" count="1" type="stmt"/> | ||
| <line num="191" count="1" type="stmt"/> | ||
| <line num="192" count="1" type="stmt"/> | ||
| <line num="193" count="1" type="stmt"/> | ||
| <line num="194" count="1" type="stmt"/> | ||
| <line num="195" count="1" type="stmt"/> | ||
| <line num="196" count="1" type="stmt"/> | ||
| <line num="197" count="1" type="cond" truecount="1" falsecount="0"/> | ||
| <line num="198" count="1" type="stmt"/> | ||
| <line num="199" count="1" type="stmt"/> | ||
| </file> | ||
| </project> | ||
| </coverage> |
| {"/Users/fiscozen/Workspace/design_system/packages/link/src/FzLink.vue": {"path":"/Users/fiscozen/Workspace/design_system/packages/link/src/FzLink.vue","all":false,"statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":3}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":19}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":2}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":92}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":90}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":88}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":2}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":42}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":97}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":60}},"11":{"start":{"line":12,"column":0},"end":{"line":12,"column":2}},"12":{"start":{"line":13,"column":0},"end":{"line":13,"column":13}},"13":{"start":{"line":14,"column":0},"end":{"line":14,"column":11}},"14":{"start":{"line":15,"column":0},"end":{"line":15,"column":61}},"15":{"start":{"line":16,"column":0},"end":{"line":16,"column":3}},"16":{"start":{"line":17,"column":0},"end":{"line":17,"column":11}},"17":{"start":{"line":18,"column":0},"end":{"line":18,"column":75}},"18":{"start":{"line":19,"column":0},"end":{"line":19,"column":3}},"19":{"start":{"line":20,"column":0},"end":{"line":20,"column":11}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":83}},"21":{"start":{"line":22,"column":0},"end":{"line":22,"column":3}},"22":{"start":{"line":23,"column":0},"end":{"line":23,"column":30}},"23":{"start":{"line":24,"column":0},"end":{"line":24,"column":37}},"24":{"start":{"line":25,"column":0},"end":{"line":25,"column":0}},"25":{"start":{"line":26,"column":0},"end":{"line":26,"column":56}},"26":{"start":{"line":27,"column":0},"end":{"line":27,"column":18}},"27":{"start":{"line":28,"column":0},"end":{"line":28,"column":23}},"28":{"start":{"line":29,"column":0},"end":{"line":29,"column":13}},"29":{"start":{"line":30,"column":0},"end":{"line":30,"column":18}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":17}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":17}},"32":{"start":{"line":33,"column":0},"end":{"line":33,"column":2}},"33":{"start":{"line":34,"column":0},"end":{"line":34,"column":0}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":3}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":68}},"36":{"start":{"line":37,"column":0},"end":{"line":37,"column":3}},"37":{"start":{"line":38,"column":0},"end":{"line":38,"column":47}},"38":{"start":{"line":39,"column":0},"end":{"line":39,"column":31}},"39":{"start":{"line":40,"column":0},"end":{"line":40,"column":31}},"40":{"start":{"line":41,"column":0},"end":{"line":41,"column":3}},"41":{"start":{"line":42,"column":0},"end":{"line":42,"column":81}},"42":{"start":{"line":43,"column":0},"end":{"line":43,"column":3}},"43":{"start":{"line":44,"column":0},"end":{"line":44,"column":39}},"44":{"start":{"line":45,"column":0},"end":{"line":45,"column":28}},"45":{"start":{"line":46,"column":0},"end":{"line":46,"column":17}},"46":{"start":{"line":47,"column":0},"end":{"line":47,"column":99}},"47":{"start":{"line":48,"column":0},"end":{"line":48,"column":91}},"48":{"start":{"line":49,"column":0},"end":{"line":49,"column":5}},"49":{"start":{"line":50,"column":0},"end":{"line":50,"column":15}},"50":{"start":{"line":51,"column":0},"end":{"line":51,"column":3}},"51":{"start":{"line":52,"column":0},"end":{"line":52,"column":2}},"52":{"start":{"line":53,"column":0},"end":{"line":53,"column":28}},"53":{"start":{"line":54,"column":0},"end":{"line":54,"column":17}},"54":{"start":{"line":55,"column":0},"end":{"line":55,"column":99}},"55":{"start":{"line":56,"column":0},"end":{"line":56,"column":91}},"56":{"start":{"line":57,"column":0},"end":{"line":57,"column":5}},"57":{"start":{"line":58,"column":0},"end":{"line":58,"column":15}},"58":{"start":{"line":59,"column":0},"end":{"line":59,"column":3}},"59":{"start":{"line":60,"column":0},"end":{"line":60,"column":2}},"60":{"start":{"line":61,"column":0},"end":{"line":61,"column":34}},"61":{"start":{"line":62,"column":0},"end":{"line":62,"column":2}},"62":{"start":{"line":63,"column":0},"end":{"line":63,"column":0}},"63":{"start":{"line":64,"column":0},"end":{"line":64,"column":3}},"64":{"start":{"line":65,"column":0},"end":{"line":65,"column":61}},"65":{"start":{"line":66,"column":0},"end":{"line":66,"column":3}},"66":{"start":{"line":67,"column":0},"end":{"line":67,"column":70}},"67":{"start":{"line":68,"column":0},"end":{"line":68,"column":66}},"68":{"start":{"line":69,"column":0},"end":{"line":69,"column":3}},"69":{"start":{"line":70,"column":0},"end":{"line":70,"column":36}},"70":{"start":{"line":71,"column":0},"end":{"line":71,"column":45}},"71":{"start":{"line":72,"column":0},"end":{"line":72,"column":3}},"72":{"start":{"line":73,"column":0},"end":{"line":73,"column":56}},"73":{"start":{"line":74,"column":0},"end":{"line":74,"column":60}},"74":{"start":{"line":75,"column":0},"end":{"line":75,"column":46}},"75":{"start":{"line":76,"column":0},"end":{"line":76,"column":3}},"76":{"start":{"line":77,"column":0},"end":{"line":77,"column":2}},"77":{"start":{"line":78,"column":0},"end":{"line":78,"column":0}},"78":{"start":{"line":79,"column":0},"end":{"line":79,"column":3}},"79":{"start":{"line":80,"column":0},"end":{"line":80,"column":42}},"80":{"start":{"line":81,"column":0},"end":{"line":81,"column":3}},"81":{"start":{"line":82,"column":0},"end":{"line":82,"column":85}},"82":{"start":{"line":83,"column":0},"end":{"line":83,"column":64}},"83":{"start":{"line":84,"column":0},"end":{"line":84,"column":3}},"84":{"start":{"line":85,"column":0},"end":{"line":85,"column":99}},"85":{"start":{"line":86,"column":0},"end":{"line":86,"column":101}},"86":{"start":{"line":87,"column":0},"end":{"line":87,"column":97}},"87":{"start":{"line":88,"column":0},"end":{"line":88,"column":99}},"88":{"start":{"line":89,"column":0},"end":{"line":89,"column":81}},"89":{"start":{"line":90,"column":0},"end":{"line":90,"column":79}},"90":{"start":{"line":91,"column":0},"end":{"line":91,"column":0}},"91":{"start":{"line":92,"column":0},"end":{"line":92,"column":3}},"92":{"start":{"line":93,"column":0},"end":{"line":93,"column":68}},"93":{"start":{"line":94,"column":0},"end":{"line":94,"column":3}},"94":{"start":{"line":95,"column":0},"end":{"line":95,"column":34}},"95":{"start":{"line":96,"column":0},"end":{"line":96,"column":44}},"96":{"start":{"line":97,"column":0},"end":{"line":97,"column":2}},"97":{"start":{"line":98,"column":0},"end":{"line":98,"column":17}},"98":{"start":{"line":99,"column":0},"end":{"line":99,"column":35}},"99":{"start":{"line":100,"column":0},"end":{"line":100,"column":85}},"100":{"start":{"line":101,"column":0},"end":{"line":101,"column":11}},"101":{"start":{"line":102,"column":0},"end":{"line":102,"column":6}},"102":{"start":{"line":103,"column":0},"end":{"line":103,"column":37}},"103":{"start":{"line":104,"column":0},"end":{"line":104,"column":104}},"104":{"start":{"line":105,"column":0},"end":{"line":105,"column":11}},"105":{"start":{"line":106,"column":0},"end":{"line":106,"column":6}},"106":{"start":{"line":107,"column":0},"end":{"line":107,"column":34}},"107":{"start":{"line":108,"column":0},"end":{"line":108,"column":115}},"108":{"start":{"line":109,"column":0},"end":{"line":109,"column":11}},"109":{"start":{"line":110,"column":0},"end":{"line":110,"column":6}},"110":{"start":{"line":111,"column":0},"end":{"line":111,"column":36}},"111":{"start":{"line":112,"column":0},"end":{"line":112,"column":134}},"112":{"start":{"line":113,"column":0},"end":{"line":113,"column":11}},"113":{"start":{"line":114,"column":0},"end":{"line":114,"column":3}},"114":{"start":{"line":115,"column":0},"end":{"line":115,"column":2}},"115":{"start":{"line":116,"column":0},"end":{"line":116,"column":20}},"116":{"start":{"line":117,"column":0},"end":{"line":117,"column":2}},"117":{"start":{"line":118,"column":0},"end":{"line":118,"column":0}},"118":{"start":{"line":119,"column":0},"end":{"line":119,"column":3}},"119":{"start":{"line":120,"column":0},"end":{"line":120,"column":58}},"120":{"start":{"line":121,"column":0},"end":{"line":121,"column":3}},"121":{"start":{"line":122,"column":0},"end":{"line":122,"column":83}},"122":{"start":{"line":123,"column":0},"end":{"line":123,"column":78}},"123":{"start":{"line":124,"column":0},"end":{"line":124,"column":3}},"124":{"start":{"line":125,"column":0},"end":{"line":125,"column":34}},"125":{"start":{"line":126,"column":0},"end":{"line":126,"column":66}},"126":{"start":{"line":127,"column":0},"end":{"line":127,"column":2}},"127":{"start":{"line":128,"column":0},"end":{"line":128,"column":17}},"128":{"start":{"line":129,"column":0},"end":{"line":129,"column":34}},"129":{"start":{"line":130,"column":0},"end":{"line":130,"column":87}},"130":{"start":{"line":131,"column":0},"end":{"line":131,"column":39}},"131":{"start":{"line":132,"column":0},"end":{"line":132,"column":11}},"132":{"start":{"line":133,"column":0},"end":{"line":133,"column":6}},"133":{"start":{"line":134,"column":0},"end":{"line":134,"column":33}},"134":{"start":{"line":135,"column":0},"end":{"line":135,"column":96}},"135":{"start":{"line":136,"column":0},"end":{"line":136,"column":49}},"136":{"start":{"line":137,"column":0},"end":{"line":137,"column":11}},"137":{"start":{"line":138,"column":0},"end":{"line":138,"column":3}},"138":{"start":{"line":139,"column":0},"end":{"line":139,"column":2}},"139":{"start":{"line":140,"column":0},"end":{"line":140,"column":20}},"140":{"start":{"line":141,"column":0},"end":{"line":141,"column":2}},"141":{"start":{"line":142,"column":0},"end":{"line":142,"column":0}},"142":{"start":{"line":143,"column":0},"end":{"line":143,"column":3}},"143":{"start":{"line":144,"column":0},"end":{"line":144,"column":33}},"144":{"start":{"line":145,"column":0},"end":{"line":145,"column":3}},"145":{"start":{"line":146,"column":0},"end":{"line":146,"column":63}},"146":{"start":{"line":147,"column":0},"end":{"line":147,"column":53}},"147":{"start":{"line":148,"column":0},"end":{"line":148,"column":3}},"148":{"start":{"line":149,"column":0},"end":{"line":149,"column":37}},"149":{"start":{"line":150,"column":0},"end":{"line":150,"column":23}},"150":{"start":{"line":151,"column":0},"end":{"line":151,"column":60}},"151":{"start":{"line":152,"column":0},"end":{"line":152,"column":29}},"152":{"start":{"line":153,"column":0},"end":{"line":153,"column":3}},"153":{"start":{"line":154,"column":0},"end":{"line":154,"column":11}},"154":{"start":{"line":155,"column":0},"end":{"line":155,"column":2}},"155":{"start":{"line":156,"column":0},"end":{"line":156,"column":0}},"156":{"start":{"line":157,"column":0},"end":{"line":157,"column":3}},"157":{"start":{"line":158,"column":0},"end":{"line":158,"column":57}},"158":{"start":{"line":159,"column":0},"end":{"line":159,"column":3}},"159":{"start":{"line":160,"column":0},"end":{"line":160,"column":79}},"160":{"start":{"line":161,"column":0},"end":{"line":161,"column":59}},"161":{"start":{"line":162,"column":0},"end":{"line":162,"column":3}},"162":{"start":{"line":163,"column":0},"end":{"line":163,"column":36}},"163":{"start":{"line":164,"column":0},"end":{"line":164,"column":52}},"164":{"start":{"line":165,"column":0},"end":{"line":165,"column":32}},"165":{"start":{"line":166,"column":0},"end":{"line":166,"column":3}},"166":{"start":{"line":167,"column":0},"end":{"line":167,"column":18}},"167":{"start":{"line":168,"column":0},"end":{"line":168,"column":2}},"168":{"start":{"line":169,"column":0},"end":{"line":169,"column":9}},"169":{"start":{"line":170,"column":0},"end":{"line":170,"column":0}},"170":{"start":{"line":171,"column":0},"end":{"line":171,"column":10}},"171":{"start":{"line":172,"column":0},"end":{"line":172,"column":7}},"172":{"start":{"line":173,"column":0},"end":{"line":173,"column":19}},"173":{"start":{"line":174,"column":0},"end":{"line":174,"column":22}},"174":{"start":{"line":175,"column":0},"end":{"line":175,"column":48}},"175":{"start":{"line":176,"column":0},"end":{"line":176,"column":15}},"176":{"start":{"line":177,"column":0},"end":{"line":177,"column":30}},"177":{"start":{"line":178,"column":0},"end":{"line":178,"column":3}},"178":{"start":{"line":179,"column":0},"end":{"line":179,"column":17}},"179":{"start":{"line":180,"column":0},"end":{"line":180,"column":9}},"180":{"start":{"line":181,"column":0},"end":{"line":181,"column":4}},"181":{"start":{"line":182,"column":0},"end":{"line":182,"column":24}},"182":{"start":{"line":183,"column":0},"end":{"line":183,"column":24}},"183":{"start":{"line":184,"column":0},"end":{"line":184,"column":22}},"184":{"start":{"line":185,"column":0},"end":{"line":185,"column":20}},"185":{"start":{"line":186,"column":0},"end":{"line":186,"column":22}},"186":{"start":{"line":187,"column":0},"end":{"line":187,"column":3}},"187":{"start":{"line":188,"column":0},"end":{"line":188,"column":17}},"188":{"start":{"line":189,"column":0},"end":{"line":189,"column":6}},"189":{"start":{"line":190,"column":0},"end":{"line":190,"column":14}},"190":{"start":{"line":191,"column":0},"end":{"line":191,"column":10}},"191":{"start":{"line":192,"column":0},"end":{"line":192,"column":12}},"192":{"start":{"line":193,"column":0},"end":{"line":193,"column":22}},"193":{"start":{"line":194,"column":0},"end":{"line":194,"column":22}},"194":{"start":{"line":195,"column":0},"end":{"line":195,"column":20}},"195":{"start":{"line":196,"column":0},"end":{"line":196,"column":3}},"196":{"start":{"line":197,"column":0},"end":{"line":197,"column":17}},"197":{"start":{"line":198,"column":0},"end":{"line":198,"column":16}},"198":{"start":{"line":199,"column":0},"end":{"line":199,"column":11}}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":1,"41":1,"42":1,"43":1,"44":37,"45":1,"46":1,"47":1,"48":1,"49":1,"50":1,"51":36,"52":37,"53":1,"54":1,"55":1,"56":1,"57":1,"58":1,"59":35,"60":35,"61":1,"62":1,"63":1,"64":1,"65":1,"66":1,"67":1,"68":1,"69":1,"70":37,"71":37,"72":37,"73":37,"74":37,"75":37,"76":1,"77":1,"78":1,"79":1,"80":1,"81":1,"82":1,"83":1,"84":1,"85":1,"86":1,"87":1,"88":1,"89":1,"90":1,"91":1,"92":1,"93":1,"94":1,"95":29,"96":29,"97":29,"98":29,"99":2,"100":2,"101":29,"102":29,"103":24,"104":24,"105":29,"106":29,"107":2,"108":2,"109":29,"110":29,"111":1,"112":1,"113":29,"114":29,"115":29,"116":1,"117":1,"118":1,"119":1,"120":1,"121":1,"122":1,"123":1,"124":1,"125":8,"126":8,"127":8,"128":8,"129":6,"130":6,"131":6,"132":8,"133":8,"134":2,"135":2,"136":2,"137":8,"138":8,"139":8,"140":1,"141":1,"142":1,"143":1,"144":1,"145":1,"146":1,"147":1,"148":1,"149":9,"150":9,"151":9,"152":9,"153":0,"154":1,"155":1,"156":1,"157":1,"158":1,"159":1,"160":1,"161":1,"162":1,"163":9,"164":2,"165":2,"166":7,"167":1,"168":1,"169":1,"170":1,"171":1,"172":1,"173":8,"174":8,"175":8,"176":8,"177":8,"178":8,"179":1,"180":1,"181":1,"182":9,"183":9,"184":9,"185":9,"186":9,"187":9,"188":1,"189":1,"190":1,"191":1,"192":1,"193":1,"194":1,"195":1,"196":1,"197":1,"198":1},"branchMap":{"0":{"type":"branch","line":44,"loc":{"start":{"line":44,"column":32},"end":{"line":62,"column":1}},"locations":[{"start":{"line":44,"column":32},"end":{"line":62,"column":1}}]},"1":{"type":"branch","line":45,"loc":{"start":{"line":45,"column":27},"end":{"line":51,"column":3}},"locations":[{"start":{"line":45,"column":27},"end":{"line":51,"column":3}}]},"2":{"type":"branch","line":51,"loc":{"start":{"line":51,"column":2},"end":{"line":53,"column":27}},"locations":[{"start":{"line":51,"column":2},"end":{"line":53,"column":27}}]},"3":{"type":"branch","line":53,"loc":{"start":{"line":53,"column":27},"end":{"line":59,"column":3}},"locations":[{"start":{"line":53,"column":27},"end":{"line":59,"column":3}}]},"4":{"type":"branch","line":59,"loc":{"start":{"line":59,"column":2},"end":{"line":61,"column":34}},"locations":[{"start":{"line":59,"column":2},"end":{"line":61,"column":34}}]},"5":{"type":"branch","line":70,"loc":{"start":{"line":70,"column":29},"end":{"line":77,"column":1}},"locations":[{"start":{"line":70,"column":29},"end":{"line":77,"column":1}}]},"6":{"type":"branch","line":85,"loc":{"start":{"line":85,"column":27},"end":{"line":85,"column":99}},"locations":[{"start":{"line":85,"column":27},"end":{"line":85,"column":99}}]},"7":{"type":"branch","line":85,"loc":{"start":{"line":85,"column":59},"end":{"line":85,"column":99}},"locations":[{"start":{"line":85,"column":59},"end":{"line":85,"column":99}}]},"8":{"type":"branch","line":86,"loc":{"start":{"line":86,"column":29},"end":{"line":86,"column":101}},"locations":[{"start":{"line":86,"column":29},"end":{"line":86,"column":101}}]},"9":{"type":"branch","line":86,"loc":{"start":{"line":86,"column":61},"end":{"line":86,"column":101}},"locations":[{"start":{"line":86,"column":61},"end":{"line":86,"column":101}}]},"10":{"type":"branch","line":87,"loc":{"start":{"line":87,"column":26},"end":{"line":87,"column":97}},"locations":[{"start":{"line":87,"column":26},"end":{"line":87,"column":97}}]},"11":{"type":"branch","line":88,"loc":{"start":{"line":88,"column":28},"end":{"line":88,"column":99}},"locations":[{"start":{"line":88,"column":28},"end":{"line":88,"column":99}}]},"12":{"type":"branch","line":89,"loc":{"start":{"line":89,"column":26},"end":{"line":89,"column":81}},"locations":[{"start":{"line":89,"column":26},"end":{"line":89,"column":81}}]},"13":{"type":"branch","line":89,"loc":{"start":{"line":89,"column":58},"end":{"line":89,"column":81}},"locations":[{"start":{"line":89,"column":58},"end":{"line":89,"column":81}}]},"14":{"type":"branch","line":90,"loc":{"start":{"line":90,"column":25},"end":{"line":90,"column":79}},"locations":[{"start":{"line":90,"column":25},"end":{"line":90,"column":79}}]},"15":{"type":"branch","line":95,"loc":{"start":{"line":95,"column":27},"end":{"line":117,"column":1}},"locations":[{"start":{"line":95,"column":27},"end":{"line":117,"column":1}}]},"16":{"type":"branch","line":99,"loc":{"start":{"line":99,"column":4},"end":{"line":101,"column":11}},"locations":[{"start":{"line":99,"column":4},"end":{"line":101,"column":11}}]},"17":{"type":"branch","line":103,"loc":{"start":{"line":103,"column":4},"end":{"line":105,"column":11}},"locations":[{"start":{"line":103,"column":4},"end":{"line":105,"column":11}}]},"18":{"type":"branch","line":107,"loc":{"start":{"line":107,"column":4},"end":{"line":109,"column":11}},"locations":[{"start":{"line":107,"column":4},"end":{"line":109,"column":11}}]},"19":{"type":"branch","line":111,"loc":{"start":{"line":111,"column":4},"end":{"line":113,"column":11}},"locations":[{"start":{"line":111,"column":4},"end":{"line":113,"column":11}}]},"20":{"type":"branch","line":125,"loc":{"start":{"line":125,"column":27},"end":{"line":141,"column":1}},"locations":[{"start":{"line":125,"column":27},"end":{"line":141,"column":1}}]},"21":{"type":"branch","line":129,"loc":{"start":{"line":129,"column":4},"end":{"line":132,"column":11}},"locations":[{"start":{"line":129,"column":4},"end":{"line":132,"column":11}}]},"22":{"type":"branch","line":134,"loc":{"start":{"line":134,"column":4},"end":{"line":137,"column":11}},"locations":[{"start":{"line":134,"column":4},"end":{"line":137,"column":11}}]},"23":{"type":"branch","line":149,"loc":{"start":{"line":149,"column":30},"end":{"line":155,"column":1}},"locations":[{"start":{"line":149,"column":30},"end":{"line":155,"column":1}}]},"24":{"type":"branch","line":153,"loc":{"start":{"line":153,"column":2},"end":{"line":154,"column":11}},"locations":[{"start":{"line":153,"column":2},"end":{"line":154,"column":11}}]},"25":{"type":"branch","line":163,"loc":{"start":{"line":163,"column":29},"end":{"line":168,"column":1}},"locations":[{"start":{"line":163,"column":29},"end":{"line":168,"column":1}}]},"26":{"type":"branch","line":164,"loc":{"start":{"line":164,"column":51},"end":{"line":166,"column":3}},"locations":[{"start":{"line":164,"column":51},"end":{"line":166,"column":3}}]},"27":{"type":"branch","line":166,"loc":{"start":{"line":166,"column":2},"end":{"line":167,"column":18}},"locations":[{"start":{"line":166,"column":2},"end":{"line":167,"column":18}}]},"28":{"type":"branch","line":173,"loc":{"start":{"line":173,"column":10},"end":{"line":179,"column":17}},"locations":[{"start":{"line":173,"column":10},"end":{"line":179,"column":17}}]},"29":{"type":"branch","line":175,"loc":{"start":{"line":175,"column":28},"end":{"line":175,"column":48}},"locations":[{"start":{"line":175,"column":28},"end":{"line":175,"column":48}}]},"30":{"type":"branch","line":182,"loc":{"start":{"line":182,"column":15},"end":{"line":188,"column":17}},"locations":[{"start":{"line":182,"column":15},"end":{"line":188,"column":17}}]},"31":{"type":"branch","line":197,"loc":{"start":{"line":197,"column":4},"end":{"line":197,"column":17}},"locations":[{"start":{"line":197,"column":4},"end":{"line":197,"column":17}}]}},"b":{"0":[37],"1":[1],"2":[36],"3":[1],"4":[35],"5":[37],"6":[29],"7":[26],"8":[27],"9":[24],"10":[3],"11":[1],"12":[8],"13":[6],"14":[2],"15":[29],"16":[2],"17":[24],"18":[2],"19":[1],"20":[8],"21":[6],"22":[2],"23":[9],"24":[0],"25":[9],"26":[2],"27":[7],"28":[8],"29":[0],"30":[9],"31":[20]},"fnMap":{"0":{"name":"isDefaultUnderline","decl":{"start":{"line":85,"column":27},"end":{"line":85,"column":99}},"loc":{"start":{"line":85,"column":27},"end":{"line":85,"column":99}},"line":85},"1":{"name":"isDefaultNoUnderline","decl":{"start":{"line":86,"column":29},"end":{"line":86,"column":101}},"loc":{"start":{"line":86,"column":29},"end":{"line":86,"column":101}},"line":86},"2":{"name":"isDangerUnderline","decl":{"start":{"line":87,"column":26},"end":{"line":87,"column":97}},"loc":{"start":{"line":87,"column":26},"end":{"line":87,"column":97}},"line":87},"3":{"name":"isDangerNoUnderline","decl":{"start":{"line":88,"column":28},"end":{"line":88,"column":99}},"loc":{"start":{"line":88,"column":28},"end":{"line":88,"column":99}},"line":88},"4":{"name":"isDefaultDisabled","decl":{"start":{"line":89,"column":26},"end":{"line":89,"column":81}},"loc":{"start":{"line":89,"column":26},"end":{"line":89,"column":81}},"line":89},"5":{"name":"isDangerDisabled","decl":{"start":{"line":90,"column":25},"end":{"line":90,"column":79}},"loc":{"start":{"line":90,"column":25},"end":{"line":90,"column":79}},"line":90}},"f":{"0":29,"1":27,"2":3,"3":1,"4":8,"5":2}} | ||
| } |
Sorry, the diff of this file is not supported yet
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <title>Code coverage report for FzLink.vue</title> | ||
| <meta charset="utf-8" /> | ||
| <link rel="stylesheet" href="prettify.css" /> | ||
| <link rel="stylesheet" href="base.css" /> | ||
| <link rel="shortcut icon" type="image/x-icon" href="favicon.png" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <style type='text/css'> | ||
| .coverage-summary .sorter { | ||
| background-image: url(sort-arrow-sprite.png); | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div class='wrapper'> | ||
| <div class='pad1'> | ||
| <h1><a href="index.html">All files</a> FzLink.vue</h1> | ||
| <div class='clearfix'> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">99.49% </span> | ||
| <span class="quiet">Statements</span> | ||
| <span class='fraction'>198/199</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">93.75% </span> | ||
| <span class="quiet">Branches</span> | ||
| <span class='fraction'>30/32</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">100% </span> | ||
| <span class="quiet">Functions</span> | ||
| <span class='fraction'>6/6</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">99.49% </span> | ||
| <span class="quiet">Lines</span> | ||
| <span class='fraction'>198/199</span> | ||
| </div> | ||
| </div> | ||
| <p class="quiet"> | ||
| 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. | ||
| </p> | ||
| <template id="filterTemplate"> | ||
| <div class="quiet"> | ||
| Filter: | ||
| <input type="search" id="fileSearch"> | ||
| </div> | ||
| </template> | ||
| </div> | ||
| <div class='status-line high'></div> | ||
| <pre><table class="coverage"> | ||
| <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a> | ||
| <a name='L2'></a><a href='#L2'>2</a> | ||
| <a name='L3'></a><a href='#L3'>3</a> | ||
| <a name='L4'></a><a href='#L4'>4</a> | ||
| <a name='L5'></a><a href='#L5'>5</a> | ||
| <a name='L6'></a><a href='#L6'>6</a> | ||
| <a name='L7'></a><a href='#L7'>7</a> | ||
| <a name='L8'></a><a href='#L8'>8</a> | ||
| <a name='L9'></a><a href='#L9'>9</a> | ||
| <a name='L10'></a><a href='#L10'>10</a> | ||
| <a name='L11'></a><a href='#L11'>11</a> | ||
| <a name='L12'></a><a href='#L12'>12</a> | ||
| <a name='L13'></a><a href='#L13'>13</a> | ||
| <a name='L14'></a><a href='#L14'>14</a> | ||
| <a name='L15'></a><a href='#L15'>15</a> | ||
| <a name='L16'></a><a href='#L16'>16</a> | ||
| <a name='L17'></a><a href='#L17'>17</a> | ||
| <a name='L18'></a><a href='#L18'>18</a> | ||
| <a name='L19'></a><a href='#L19'>19</a> | ||
| <a name='L20'></a><a href='#L20'>20</a> | ||
| <a name='L21'></a><a href='#L21'>21</a> | ||
| <a name='L22'></a><a href='#L22'>22</a> | ||
| <a name='L23'></a><a href='#L23'>23</a> | ||
| <a name='L24'></a><a href='#L24'>24</a> | ||
| <a name='L25'></a><a href='#L25'>25</a> | ||
| <a name='L26'></a><a href='#L26'>26</a> | ||
| <a name='L27'></a><a href='#L27'>27</a> | ||
| <a name='L28'></a><a href='#L28'>28</a> | ||
| <a name='L29'></a><a href='#L29'>29</a> | ||
| <a name='L30'></a><a href='#L30'>30</a> | ||
| <a name='L31'></a><a href='#L31'>31</a> | ||
| <a name='L32'></a><a href='#L32'>32</a> | ||
| <a name='L33'></a><a href='#L33'>33</a> | ||
| <a name='L34'></a><a href='#L34'>34</a> | ||
| <a name='L35'></a><a href='#L35'>35</a> | ||
| <a name='L36'></a><a href='#L36'>36</a> | ||
| <a name='L37'></a><a href='#L37'>37</a> | ||
| <a name='L38'></a><a href='#L38'>38</a> | ||
| <a name='L39'></a><a href='#L39'>39</a> | ||
| <a name='L40'></a><a href='#L40'>40</a> | ||
| <a name='L41'></a><a href='#L41'>41</a> | ||
| <a name='L42'></a><a href='#L42'>42</a> | ||
| <a name='L43'></a><a href='#L43'>43</a> | ||
| <a name='L44'></a><a href='#L44'>44</a> | ||
| <a name='L45'></a><a href='#L45'>45</a> | ||
| <a name='L46'></a><a href='#L46'>46</a> | ||
| <a name='L47'></a><a href='#L47'>47</a> | ||
| <a name='L48'></a><a href='#L48'>48</a> | ||
| <a name='L49'></a><a href='#L49'>49</a> | ||
| <a name='L50'></a><a href='#L50'>50</a> | ||
| <a name='L51'></a><a href='#L51'>51</a> | ||
| <a name='L52'></a><a href='#L52'>52</a> | ||
| <a name='L53'></a><a href='#L53'>53</a> | ||
| <a name='L54'></a><a href='#L54'>54</a> | ||
| <a name='L55'></a><a href='#L55'>55</a> | ||
| <a name='L56'></a><a href='#L56'>56</a> | ||
| <a name='L57'></a><a href='#L57'>57</a> | ||
| <a name='L58'></a><a href='#L58'>58</a> | ||
| <a name='L59'></a><a href='#L59'>59</a> | ||
| <a name='L60'></a><a href='#L60'>60</a> | ||
| <a name='L61'></a><a href='#L61'>61</a> | ||
| <a name='L62'></a><a href='#L62'>62</a> | ||
| <a name='L63'></a><a href='#L63'>63</a> | ||
| <a name='L64'></a><a href='#L64'>64</a> | ||
| <a name='L65'></a><a href='#L65'>65</a> | ||
| <a name='L66'></a><a href='#L66'>66</a> | ||
| <a name='L67'></a><a href='#L67'>67</a> | ||
| <a name='L68'></a><a href='#L68'>68</a> | ||
| <a name='L69'></a><a href='#L69'>69</a> | ||
| <a name='L70'></a><a href='#L70'>70</a> | ||
| <a name='L71'></a><a href='#L71'>71</a> | ||
| <a name='L72'></a><a href='#L72'>72</a> | ||
| <a name='L73'></a><a href='#L73'>73</a> | ||
| <a name='L74'></a><a href='#L74'>74</a> | ||
| <a name='L75'></a><a href='#L75'>75</a> | ||
| <a name='L76'></a><a href='#L76'>76</a> | ||
| <a name='L77'></a><a href='#L77'>77</a> | ||
| <a name='L78'></a><a href='#L78'>78</a> | ||
| <a name='L79'></a><a href='#L79'>79</a> | ||
| <a name='L80'></a><a href='#L80'>80</a> | ||
| <a name='L81'></a><a href='#L81'>81</a> | ||
| <a name='L82'></a><a href='#L82'>82</a> | ||
| <a name='L83'></a><a href='#L83'>83</a> | ||
| <a name='L84'></a><a href='#L84'>84</a> | ||
| <a name='L85'></a><a href='#L85'>85</a> | ||
| <a name='L86'></a><a href='#L86'>86</a> | ||
| <a name='L87'></a><a href='#L87'>87</a> | ||
| <a name='L88'></a><a href='#L88'>88</a> | ||
| <a name='L89'></a><a href='#L89'>89</a> | ||
| <a name='L90'></a><a href='#L90'>90</a> | ||
| <a name='L91'></a><a href='#L91'>91</a> | ||
| <a name='L92'></a><a href='#L92'>92</a> | ||
| <a name='L93'></a><a href='#L93'>93</a> | ||
| <a name='L94'></a><a href='#L94'>94</a> | ||
| <a name='L95'></a><a href='#L95'>95</a> | ||
| <a name='L96'></a><a href='#L96'>96</a> | ||
| <a name='L97'></a><a href='#L97'>97</a> | ||
| <a name='L98'></a><a href='#L98'>98</a> | ||
| <a name='L99'></a><a href='#L99'>99</a> | ||
| <a name='L100'></a><a href='#L100'>100</a> | ||
| <a name='L101'></a><a href='#L101'>101</a> | ||
| <a name='L102'></a><a href='#L102'>102</a> | ||
| <a name='L103'></a><a href='#L103'>103</a> | ||
| <a name='L104'></a><a href='#L104'>104</a> | ||
| <a name='L105'></a><a href='#L105'>105</a> | ||
| <a name='L106'></a><a href='#L106'>106</a> | ||
| <a name='L107'></a><a href='#L107'>107</a> | ||
| <a name='L108'></a><a href='#L108'>108</a> | ||
| <a name='L109'></a><a href='#L109'>109</a> | ||
| <a name='L110'></a><a href='#L110'>110</a> | ||
| <a name='L111'></a><a href='#L111'>111</a> | ||
| <a name='L112'></a><a href='#L112'>112</a> | ||
| <a name='L113'></a><a href='#L113'>113</a> | ||
| <a name='L114'></a><a href='#L114'>114</a> | ||
| <a name='L115'></a><a href='#L115'>115</a> | ||
| <a name='L116'></a><a href='#L116'>116</a> | ||
| <a name='L117'></a><a href='#L117'>117</a> | ||
| <a name='L118'></a><a href='#L118'>118</a> | ||
| <a name='L119'></a><a href='#L119'>119</a> | ||
| <a name='L120'></a><a href='#L120'>120</a> | ||
| <a name='L121'></a><a href='#L121'>121</a> | ||
| <a name='L122'></a><a href='#L122'>122</a> | ||
| <a name='L123'></a><a href='#L123'>123</a> | ||
| <a name='L124'></a><a href='#L124'>124</a> | ||
| <a name='L125'></a><a href='#L125'>125</a> | ||
| <a name='L126'></a><a href='#L126'>126</a> | ||
| <a name='L127'></a><a href='#L127'>127</a> | ||
| <a name='L128'></a><a href='#L128'>128</a> | ||
| <a name='L129'></a><a href='#L129'>129</a> | ||
| <a name='L130'></a><a href='#L130'>130</a> | ||
| <a name='L131'></a><a href='#L131'>131</a> | ||
| <a name='L132'></a><a href='#L132'>132</a> | ||
| <a name='L133'></a><a href='#L133'>133</a> | ||
| <a name='L134'></a><a href='#L134'>134</a> | ||
| <a name='L135'></a><a href='#L135'>135</a> | ||
| <a name='L136'></a><a href='#L136'>136</a> | ||
| <a name='L137'></a><a href='#L137'>137</a> | ||
| <a name='L138'></a><a href='#L138'>138</a> | ||
| <a name='L139'></a><a href='#L139'>139</a> | ||
| <a name='L140'></a><a href='#L140'>140</a> | ||
| <a name='L141'></a><a href='#L141'>141</a> | ||
| <a name='L142'></a><a href='#L142'>142</a> | ||
| <a name='L143'></a><a href='#L143'>143</a> | ||
| <a name='L144'></a><a href='#L144'>144</a> | ||
| <a name='L145'></a><a href='#L145'>145</a> | ||
| <a name='L146'></a><a href='#L146'>146</a> | ||
| <a name='L147'></a><a href='#L147'>147</a> | ||
| <a name='L148'></a><a href='#L148'>148</a> | ||
| <a name='L149'></a><a href='#L149'>149</a> | ||
| <a name='L150'></a><a href='#L150'>150</a> | ||
| <a name='L151'></a><a href='#L151'>151</a> | ||
| <a name='L152'></a><a href='#L152'>152</a> | ||
| <a name='L153'></a><a href='#L153'>153</a> | ||
| <a name='L154'></a><a href='#L154'>154</a> | ||
| <a name='L155'></a><a href='#L155'>155</a> | ||
| <a name='L156'></a><a href='#L156'>156</a> | ||
| <a name='L157'></a><a href='#L157'>157</a> | ||
| <a name='L158'></a><a href='#L158'>158</a> | ||
| <a name='L159'></a><a href='#L159'>159</a> | ||
| <a name='L160'></a><a href='#L160'>160</a> | ||
| <a name='L161'></a><a href='#L161'>161</a> | ||
| <a name='L162'></a><a href='#L162'>162</a> | ||
| <a name='L163'></a><a href='#L163'>163</a> | ||
| <a name='L164'></a><a href='#L164'>164</a> | ||
| <a name='L165'></a><a href='#L165'>165</a> | ||
| <a name='L166'></a><a href='#L166'>166</a> | ||
| <a name='L167'></a><a href='#L167'>167</a> | ||
| <a name='L168'></a><a href='#L168'>168</a> | ||
| <a name='L169'></a><a href='#L169'>169</a> | ||
| <a name='L170'></a><a href='#L170'>170</a> | ||
| <a name='L171'></a><a href='#L171'>171</a> | ||
| <a name='L172'></a><a href='#L172'>172</a> | ||
| <a name='L173'></a><a href='#L173'>173</a> | ||
| <a name='L174'></a><a href='#L174'>174</a> | ||
| <a name='L175'></a><a href='#L175'>175</a> | ||
| <a name='L176'></a><a href='#L176'>176</a> | ||
| <a name='L177'></a><a href='#L177'>177</a> | ||
| <a name='L178'></a><a href='#L178'>178</a> | ||
| <a name='L179'></a><a href='#L179'>179</a> | ||
| <a name='L180'></a><a href='#L180'>180</a> | ||
| <a name='L181'></a><a href='#L181'>181</a> | ||
| <a name='L182'></a><a href='#L182'>182</a> | ||
| <a name='L183'></a><a href='#L183'>183</a> | ||
| <a name='L184'></a><a href='#L184'>184</a> | ||
| <a name='L185'></a><a href='#L185'>185</a> | ||
| <a name='L186'></a><a href='#L186'>186</a> | ||
| <a name='L187'></a><a href='#L187'>187</a> | ||
| <a name='L188'></a><a href='#L188'>188</a> | ||
| <a name='L189'></a><a href='#L189'>189</a> | ||
| <a name='L190'></a><a href='#L190'>190</a> | ||
| <a name='L191'></a><a href='#L191'>191</a> | ||
| <a name='L192'></a><a href='#L192'>192</a> | ||
| <a name='L193'></a><a href='#L193'>193</a> | ||
| <a name='L194'></a><a href='#L194'>194</a> | ||
| <a name='L195'></a><a href='#L195'>195</a> | ||
| <a name='L196'></a><a href='#L196'>196</a> | ||
| <a name='L197'></a><a href='#L197'>197</a> | ||
| <a name='L198'></a><a href='#L198'>198</a> | ||
| <a name='L199'></a><a href='#L199'>199</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">36x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">35x</span> | ||
| <span class="cline-any cline-yes">35x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">37x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">24x</span> | ||
| <span class="cline-any cline-yes">24x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">29x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">6x</span> | ||
| <span class="cline-any cline-yes">6x</span> | ||
| <span class="cline-any cline-yes">6x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-no"> </span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">2x</span> | ||
| <span class="cline-any cline-yes">7x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">8x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">9x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span> | ||
| <span class="cline-any cline-yes">1x</span></td><td class="text"><pre class="prettyprint lang-js"><script setup lang="ts"> | ||
| /** | ||
| * FzLink Component | ||
| * | ||
| * Flexible link component supporting internal routing (vue-router) and external navigation. | ||
| * Automatically renders as router-link for internal routes, anchor tag for external URLs, | ||
| * or non-interactive span when disabled. Provides consistent styling and accessibility. | ||
| * | ||
| * TypeScript enforces correct prop types: | ||
| * - Internal links (external=false or undefined): to accepts RouteLocationRaw (string or object) | ||
| * - External links (external=true): to must be a string URL | ||
| * | ||
| * @component | ||
| * @example | ||
| * <FzLink to="/dashboard" size="md">Go to Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User Profile</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">External Site</FzLink> | ||
| */ | ||
| import { computed } from 'vue' | ||
| import { FzLinkProps } from './types' | ||
| | ||
| const props = withDefaults(defineProps<FzLinkProps>(), { | ||
| type: 'default', | ||
| linkStyle: 'default', | ||
| size: 'md', | ||
| disabled: false, | ||
| replace: false, | ||
| external: false | ||
| }) | ||
| | ||
| /** | ||
| * Normalizes deprecated size values and shows deprecation warnings. | ||
| * | ||
| * Maps deprecated sizes to their replacements: | ||
| * - 'xs' → 'sm' (with warning) | ||
| * - 'lg' → 'md' (with warning) | ||
| * | ||
| * This ensures backward compatibility while encouraging migration to new values. | ||
| */ | ||
| const normalizedSize = computed(() => { | ||
| if (props.size === 'xs') { | ||
| console.warn( | ||
| '[FzLink] The size prop value "xs" is deprecated and will be removed in a future version. ' + | ||
| 'Please use "sm" instead. The component will automatically map "xs" to "sm" for now.' | ||
| ) | ||
| return 'sm' | ||
| } | ||
| if (props.size === 'lg') { | ||
| console.warn( | ||
| '[FzLink] The size prop value "lg" is deprecated and will be removed in a future version. ' + | ||
| 'Please use "md" instead. The component will automatically map "lg" to "md" for now.' | ||
| ) | ||
| return 'md' | ||
| } | ||
| return props.size as 'sm' | 'md' | ||
| }) | ||
| | ||
| /** | ||
| * Base classes shared between link and disabled span states. | ||
| * | ||
| * Includes size-based text classes and conditional underline styling. | ||
| * Border classes provide consistent spacing for focus indicators. | ||
| */ | ||
| const commonClass = computed(() => [ | ||
| 'border-1 border-transparent inline-block', | ||
| { | ||
| 'text-sm leading-xs': normalizedSize.value === 'sm', | ||
| 'text-base leading-base': normalizedSize.value === 'md', | ||
| underline: props.linkStyle === 'underline' | ||
| } | ||
| ]) | ||
| | ||
| /** | ||
| * Helper functions to identify UI states. | ||
| * | ||
| * These functions explicitly describe when each UI representation should be applied, | ||
| * making the component logic more declarative and maintainable. | ||
| */ | ||
| const isDefaultUnderline = (p: typeof props) => p.type === 'default' && p.linkStyle === 'underline' | ||
| const isDefaultNoUnderline = (p: typeof props) => p.type === 'default' && p.linkStyle !== 'underline' | ||
| const isDangerUnderline = (p: typeof props) => p.type === 'danger' && p.linkStyle === 'underline' | ||
| const isDangerNoUnderline = (p: typeof props) => p.type === 'danger' && p.linkStyle !== 'underline' | ||
| const isDefaultDisabled = (p: typeof props) => p.type === 'default' && p.disabled | ||
| const isDangerDisabled = (p: typeof props) => p.type === 'danger' && p.disabled | ||
| | ||
| /** | ||
| * CSS classes for interactive link states (router-link and anchor). | ||
| */ | ||
| const linkClass = computed(() => { | ||
| const baseClasses = [...commonClass.value] | ||
| switch (true) { | ||
| case isDefaultUnderline(props): | ||
| baseClasses.push('text-blue-500', 'hover:text-blue-600', 'focus:text-blue-600') | ||
| break | ||
| case isDefaultNoUnderline(props): | ||
| baseClasses.push('text-blue-500', 'hover:text-blue-600', 'hover:underline', 'focus:text-blue-600') | ||
| break | ||
| case isDangerUnderline(props): | ||
| baseClasses.push('text-semantic-error-200', 'hover:text-semantic-error-300', 'focus:text-semantic-error-300') | ||
| break | ||
| case isDangerNoUnderline(props): | ||
| baseClasses.push('text-semantic-error-200', 'hover:text-semantic-error-300', 'hover:underline', 'focus:text-semantic-error-300') | ||
| break | ||
| } | ||
| return baseClasses | ||
| }) | ||
| | ||
| /** | ||
| * CSS classes for disabled link state (rendered as span). | ||
| * | ||
| * Uses switch(true) pattern to explicitly map disabled UI states to their styling. | ||
| * Each case represents a distinct visual representation of the disabled link. | ||
| */ | ||
| const spanClass = computed(() => { | ||
| const baseClasses = [...commonClass.value, 'cursor-not-allowed'] | ||
| switch (true) { | ||
| case isDefaultDisabled(props): | ||
| // Default type disabled: blue-200, underline preserved if linkStyle is underline | ||
| baseClasses.push('text-blue-200') | ||
| break | ||
| case isDangerDisabled(props): | ||
| // Danger type disabled: semantic-error-100, underline preserved if linkStyle is underline | ||
| baseClasses.push('text-semantic-error-100') | ||
| break | ||
| } | ||
| return baseClasses | ||
| }) | ||
| | ||
| /** | ||
| * Href value for external links. | ||
| * | ||
| * When external is true, TypeScript guarantees to is a string. | ||
| * This computed ensures type safety in the template. | ||
| */ | ||
| const externalHref = computed(() => { | ||
| if (props.external) { | ||
| // TypeScript narrows to to string when external is true | ||
| return props.to as string | ||
| <span class="branch-0 cbranch-no" title="branch not covered" > }</span> | ||
| <span class="cstat-no" title="statement not covered" > return ''</span> | ||
| }) | ||
| | ||
| /** | ||
| * Rel attribute for external links with target="_blank". | ||
| * | ||
| * Adds security attributes (noopener noreferrer) when opening links in new tab | ||
| * to prevent security vulnerabilities and improve privacy. | ||
| */ | ||
| const externalRel = computed(() => { | ||
| if (props.external && props.target === '_blank') { | ||
| return 'noopener noreferrer' | ||
| } | ||
| return undefined | ||
| }) | ||
| </script> | ||
| | ||
| <template> | ||
| <span | ||
| v-if="disabled" | ||
| :class="spanClass" | ||
| :aria-disabled="disabled<span class="branch-0 cbranch-no" title="branch not covered" > ? 'true' : 'false'"</span> | ||
| role="link" | ||
| aria-label="Link disabled" | ||
| > | ||
| <slot></slot> | ||
| </span> | ||
| <a | ||
| v-else-if="external" | ||
| :href="externalHref" | ||
| :class="linkClass" | ||
| :target="target" | ||
| :rel="externalRel" | ||
| > | ||
| <slot></slot> | ||
| </a> | ||
| <router-link | ||
| v-else | ||
| :to="to" | ||
| :replace="replace" | ||
| :class="linkClass" | ||
| :target="target" | ||
| > | ||
| <slot></slot> | ||
| </router-link> | ||
| </template></pre></td></tr></table></pre> | ||
| <div class='push'></div><!-- for sticky footer --> | ||
| </div><!-- /wrapper --> | ||
| <div class='footer quiet pad2 space-top1 center small'> | ||
| Code coverage generated by | ||
| <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> | ||
| at 2025-11-07T13:46:35.098Z | ||
| </div> | ||
| <script src="prettify.js"></script> | ||
| <script> | ||
| window.onload = function () { | ||
| prettyPrint(); | ||
| }; | ||
| </script> | ||
| <script src="sorter.js"></script> | ||
| <script src="block-navigation.js"></script> | ||
| </body> | ||
| </html> | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <title>Code coverage report for All files</title> | ||
| <meta charset="utf-8" /> | ||
| <link rel="stylesheet" href="prettify.css" /> | ||
| <link rel="stylesheet" href="base.css" /> | ||
| <link rel="shortcut icon" type="image/x-icon" href="favicon.png" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <style type='text/css'> | ||
| .coverage-summary .sorter { | ||
| background-image: url(sort-arrow-sprite.png); | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div class='wrapper'> | ||
| <div class='pad1'> | ||
| <h1>All files</h1> | ||
| <div class='clearfix'> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">99.49% </span> | ||
| <span class="quiet">Statements</span> | ||
| <span class='fraction'>198/199</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">93.75% </span> | ||
| <span class="quiet">Branches</span> | ||
| <span class='fraction'>30/32</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">100% </span> | ||
| <span class="quiet">Functions</span> | ||
| <span class='fraction'>6/6</span> | ||
| </div> | ||
| <div class='fl pad1y space-right2'> | ||
| <span class="strong">99.49% </span> | ||
| <span class="quiet">Lines</span> | ||
| <span class='fraction'>198/199</span> | ||
| </div> | ||
| </div> | ||
| <p class="quiet"> | ||
| 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. | ||
| </p> | ||
| <template id="filterTemplate"> | ||
| <div class="quiet"> | ||
| Filter: | ||
| <input type="search" id="fileSearch"> | ||
| </div> | ||
| </template> | ||
| </div> | ||
| <div class='status-line high'></div> | ||
| <div class="pad1"> | ||
| <table class="coverage-summary"> | ||
| <thead> | ||
| <tr> | ||
| <th data-col="file" data-fmt="html" data-html="true" class="file">File</th> | ||
| <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th> | ||
| <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th> | ||
| <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th> | ||
| <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th> | ||
| <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th> | ||
| <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th> | ||
| <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th> | ||
| <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th> | ||
| <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th> | ||
| </tr> | ||
| </thead> | ||
| <tbody><tr> | ||
| <td class="file high" data-value="FzLink.vue"><a href="FzLink.vue.html">FzLink.vue</a></td> | ||
| <td data-value="99.49" class="pic high"> | ||
| <div class="chart"><div class="cover-fill" style="width: 99%"></div><div class="cover-empty" style="width: 1%"></div></div> | ||
| </td> | ||
| <td data-value="99.49" class="pct high">99.49%</td> | ||
| <td data-value="199" class="abs high">198/199</td> | ||
| <td data-value="93.75" class="pct high">93.75%</td> | ||
| <td data-value="32" class="abs high">30/32</td> | ||
| <td data-value="100" class="pct high">100%</td> | ||
| <td data-value="6" class="abs high">6/6</td> | ||
| <td data-value="99.49" class="pct high">99.49%</td> | ||
| <td data-value="199" class="abs high">198/199</td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
| <div class='push'></div><!-- for sticky footer --> | ||
| </div><!-- /wrapper --> | ||
| <div class='footer quiet pad2 space-top1 center small'> | ||
| Code coverage generated by | ||
| <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> | ||
| at 2025-11-07T13:46:35.098Z | ||
| </div> | ||
| <script src="prettify.js"></script> | ||
| <script> | ||
| window.onload = function () { | ||
| prettyPrint(); | ||
| }; | ||
| </script> | ||
| <script src="sorter.js"></script> | ||
| <script src="block-navigation.js"></script> | ||
| </body> | ||
| </html> | ||
| .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} |
| /* eslint-disable */ | ||
| 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"]); |
Sorry, the diff of this file is not supported yet
| /* eslint-disable */ | ||
| var addSorting = (function() { | ||
| 'use strict'; | ||
| var cols, | ||
| currentSort = { | ||
| index: 0, | ||
| desc: false | ||
| }; | ||
| // returns the summary table element | ||
| function getTable() { | ||
| return document.querySelector('.coverage-summary'); | ||
| } | ||
| // returns the thead element of the summary table | ||
| function getTableHeader() { | ||
| return getTable().querySelector('thead tr'); | ||
| } | ||
| // returns the tbody element of the summary table | ||
| function getTableBody() { | ||
| return getTable().querySelector('tbody'); | ||
| } | ||
| // returns the th element for nth column | ||
| function getNthColumn(n) { | ||
| return getTableHeader().querySelectorAll('th')[n]; | ||
| } | ||
| function onFilterInput() { | ||
| const searchValue = document.getElementById('fileSearch').value; | ||
| const rows = document.getElementsByTagName('tbody')[0].children; | ||
| for (let i = 0; i < rows.length; i++) { | ||
| const row = rows[i]; | ||
| if ( | ||
| row.textContent | ||
| .toLowerCase() | ||
| .includes(searchValue.toLowerCase()) | ||
| ) { | ||
| row.style.display = ''; | ||
| } else { | ||
| row.style.display = 'none'; | ||
| } | ||
| } | ||
| } | ||
| // loads the search box | ||
| function addSearchBox() { | ||
| var template = document.getElementById('filterTemplate'); | ||
| var templateClone = template.content.cloneNode(true); | ||
| templateClone.getElementById('fileSearch').oninput = onFilterInput; | ||
| template.parentElement.appendChild(templateClone); | ||
| } | ||
| // loads all columns | ||
| function loadColumns() { | ||
| var colNodes = getTableHeader().querySelectorAll('th'), | ||
| colNode, | ||
| cols = [], | ||
| col, | ||
| i; | ||
| for (i = 0; i < colNodes.length; i += 1) { | ||
| colNode = colNodes[i]; | ||
| col = { | ||
| key: colNode.getAttribute('data-col'), | ||
| sortable: !colNode.getAttribute('data-nosort'), | ||
| type: colNode.getAttribute('data-type') || 'string' | ||
| }; | ||
| cols.push(col); | ||
| if (col.sortable) { | ||
| col.defaultDescSort = col.type === 'number'; | ||
| colNode.innerHTML = | ||
| colNode.innerHTML + '<span class="sorter"></span>'; | ||
| } | ||
| } | ||
| return cols; | ||
| } | ||
| // attaches a data attribute to every tr element with an object | ||
| // of data values keyed by column name | ||
| function loadRowData(tableRow) { | ||
| var tableCols = tableRow.querySelectorAll('td'), | ||
| colNode, | ||
| col, | ||
| data = {}, | ||
| i, | ||
| val; | ||
| for (i = 0; i < tableCols.length; i += 1) { | ||
| colNode = tableCols[i]; | ||
| col = cols[i]; | ||
| val = colNode.getAttribute('data-value'); | ||
| if (col.type === 'number') { | ||
| val = Number(val); | ||
| } | ||
| data[col.key] = val; | ||
| } | ||
| return data; | ||
| } | ||
| // loads all row data | ||
| function loadData() { | ||
| var rows = getTableBody().querySelectorAll('tr'), | ||
| i; | ||
| for (i = 0; i < rows.length; i += 1) { | ||
| rows[i].data = loadRowData(rows[i]); | ||
| } | ||
| } | ||
| // sorts the table using the data for the ith column | ||
| function sortByIndex(index, desc) { | ||
| var key = cols[index].key, | ||
| sorter = function(a, b) { | ||
| a = a.data[key]; | ||
| b = b.data[key]; | ||
| return a < b ? -1 : a > b ? 1 : 0; | ||
| }, | ||
| finalSorter = sorter, | ||
| tableBody = document.querySelector('.coverage-summary tbody'), | ||
| rowNodes = tableBody.querySelectorAll('tr'), | ||
| rows = [], | ||
| i; | ||
| if (desc) { | ||
| finalSorter = function(a, b) { | ||
| return -1 * sorter(a, b); | ||
| }; | ||
| } | ||
| for (i = 0; i < rowNodes.length; i += 1) { | ||
| rows.push(rowNodes[i]); | ||
| tableBody.removeChild(rowNodes[i]); | ||
| } | ||
| rows.sort(finalSorter); | ||
| for (i = 0; i < rows.length; i += 1) { | ||
| tableBody.appendChild(rows[i]); | ||
| } | ||
| } | ||
| // removes sort indicators for current column being sorted | ||
| function removeSortIndicators() { | ||
| var col = getNthColumn(currentSort.index), | ||
| cls = col.className; | ||
| cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); | ||
| col.className = cls; | ||
| } | ||
| // adds sort indicators for current column being sorted | ||
| function addSortIndicators() { | ||
| getNthColumn(currentSort.index).className += currentSort.desc | ||
| ? ' sorted-desc' | ||
| : ' sorted'; | ||
| } | ||
| // adds event listeners for all sorter widgets | ||
| function enableUI() { | ||
| var i, | ||
| el, | ||
| ithSorter = function ithSorter(i) { | ||
| var col = cols[i]; | ||
| return function() { | ||
| var desc = col.defaultDescSort; | ||
| if (currentSort.index === i) { | ||
| desc = !currentSort.desc; | ||
| } | ||
| sortByIndex(i, desc); | ||
| removeSortIndicators(); | ||
| currentSort.index = i; | ||
| currentSort.desc = desc; | ||
| addSortIndicators(); | ||
| }; | ||
| }; | ||
| for (i = 0; i < cols.length; i += 1) { | ||
| if (cols[i].sortable) { | ||
| // add the click event handler on the th so users | ||
| // dont have to click on those tiny arrows | ||
| el = getNthColumn(i).querySelector('.sorter').parentElement; | ||
| if (el.addEventListener) { | ||
| el.addEventListener('click', ithSorter(i)); | ||
| } else { | ||
| el.attachEvent('onclick', ithSorter(i)); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| // adds sorting functionality to the UI | ||
| return function() { | ||
| if (!getTable()) { | ||
| return; | ||
| } | ||
| cols = loadColumns(); | ||
| loadData(); | ||
| addSearchBox(); | ||
| addSortIndicators(); | ||
| enableUI(); | ||
| }; | ||
| })(); | ||
| window.addEventListener('load', addSorting); |
Sorry, the diff of this file is not supported yet
| import { describe, it, expect, vi } from 'vitest' | ||
| import { mount } from '@vue/test-utils' | ||
| import FzLink from '../FzLink.vue' | ||
| import { createRouter, createWebHistory } from 'vue-router' | ||
| const router = createRouter({ | ||
| history: createWebHistory(), | ||
| routes: [ | ||
| { name: '', path: '/example', component: () => {} }, | ||
| { name: 'route-name', path: '/route/:id', component: () => {} } | ||
| ] | ||
| }) | ||
| describe('FzLink', () => { | ||
| describe('Rendering', () => { | ||
| it('matches snapshot', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| expect(wrapper.html()).toMatchSnapshot() | ||
| }) | ||
| it('renders router-link when not disabled and not external', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| // router-link renders as <a> tag, so we check for the anchor | ||
| expect(wrapper.find('a').exists()).toBe(true) | ||
| // Verify it's not an external link (no href attribute, uses router-link) | ||
| const link = wrapper.find('a') | ||
| // router-link doesn't have href in test environment, it uses to prop | ||
| expect(link.exists()).toBe(true) | ||
| }) | ||
| it('renders anchor tag when external', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| expect(wrapper.find('a').exists()).toBe(true) | ||
| expect(wrapper.find('router-link-stub').exists()).toBe(false) | ||
| expect(wrapper.find('a').attributes('href')).toBe('https://example.com') | ||
| }) | ||
| it('renders span when disabled', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| expect(wrapper.find('span').exists()).toBe(true) | ||
| expect(wrapper.find('a').exists()).toBe(false) | ||
| expect(wrapper.find('router-link-stub').exists()).toBe(false) | ||
| }) | ||
| it('renders slot content', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'Link text content' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| expect(wrapper.html()).toContain('Link text content') | ||
| }) | ||
| }) | ||
| describe('Props: type', () => { | ||
| it('applies default type classes with default linkStyle', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'default', | ||
| linkStyle: 'default' | ||
| }, | ||
| slots: { | ||
| default: 'Default link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-blue-500') | ||
| expect(link.classes()).toContain('hover:text-blue-600') | ||
| expect(link.classes()).toContain('hover:underline') | ||
| expect(link.classes()).toContain('focus:text-blue-600') | ||
| expect(link.classes()).toContain('focus:outline-none') | ||
| expect(link.classes()).toContain('focus:border-solid') | ||
| expect(link.classes()).toContain('focus:no-underline') | ||
| expect(link.classes()).toContain('focus:border-blue-600') | ||
| expect(link.classes()).not.toContain('underline') | ||
| }) | ||
| it('applies default type classes with underline linkStyle', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'default', | ||
| linkStyle: 'underline' | ||
| }, | ||
| slots: { | ||
| default: 'Default underline link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-blue-500') | ||
| expect(link.classes()).toContain('underline') | ||
| expect(link.classes()).toContain('hover:text-blue-600') | ||
| expect(link.classes()).toContain('focus:text-blue-600') | ||
| expect(link.classes()).toContain('focus:outline-none') | ||
| expect(link.classes()).toContain('focus:border-solid') | ||
| expect(link.classes()).toContain('focus:no-underline') | ||
| expect(link.classes()).toContain('focus:border-blue-600') | ||
| }) | ||
| it('applies danger type classes with default linkStyle', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'danger', | ||
| linkStyle: 'default' | ||
| }, | ||
| slots: { | ||
| default: 'Danger link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-semantic-error-200') | ||
| expect(link.classes()).toContain('hover:text-semantic-error-300') | ||
| expect(link.classes()).toContain('hover:underline') | ||
| expect(link.classes()).toContain('focus:text-semantic-error-300') | ||
| expect(link.classes()).toContain('focus:outline-none') | ||
| expect(link.classes()).toContain('focus:border-solid') | ||
| expect(link.classes()).toContain('focus:no-underline') | ||
| expect(link.classes()).toContain('focus:border-semantic-error-300') | ||
| expect(link.classes()).not.toContain('underline') | ||
| }) | ||
| it('applies danger type classes with underline linkStyle', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'danger', | ||
| linkStyle: 'underline' | ||
| }, | ||
| slots: { | ||
| default: 'Danger underline link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-semantic-error-200') | ||
| expect(link.classes()).toContain('underline') | ||
| expect(link.classes()).toContain('hover:text-semantic-error-300') | ||
| expect(link.classes()).toContain('focus:text-semantic-error-300') | ||
| expect(link.classes()).toContain('focus:outline-none') | ||
| expect(link.classes()).toContain('focus:border-solid') | ||
| expect(link.classes()).toContain('focus:no-underline') | ||
| expect(link.classes()).toContain('focus:border-semantic-error-300') | ||
| }) | ||
| it('applies default type disabled classes', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'default', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled default link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('text-blue-200') | ||
| }) | ||
| it('applies default type disabled classes with underline', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'default', | ||
| linkStyle: 'underline', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled default underline link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('text-blue-200') | ||
| expect(span.classes()).toContain('underline') | ||
| }) | ||
| it('applies danger type disabled classes', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'danger', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled danger link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('text-semantic-error-100') | ||
| }) | ||
| it('applies danger type disabled classes with underline', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'danger', | ||
| linkStyle: 'underline', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled danger underline link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('text-semantic-error-100') | ||
| expect(span.classes()).toContain('underline') | ||
| }) | ||
| }) | ||
| describe('Props: linkStyle', () => { | ||
| it('applies default linkStyle (no underline by default)', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| linkStyle: 'default' | ||
| }, | ||
| slots: { | ||
| default: 'Default style' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).not.toContain('underline') | ||
| expect(link.classes()).toContain('hover:underline') | ||
| }) | ||
| it('applies underline linkStyle', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| linkStyle: 'underline' | ||
| }, | ||
| slots: { | ||
| default: 'Underline style' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('underline') | ||
| }) | ||
| }) | ||
| describe('Props: size', () => { | ||
| it('applies sm size classes (text-sm + leading-xs)', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| size: 'sm' | ||
| }, | ||
| slots: { | ||
| default: 'Link text' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-sm') | ||
| expect(link.classes()).toContain('leading-xs') | ||
| }) | ||
| it('applies md size classes (text-base + leading-base)', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| size: 'md' | ||
| }, | ||
| slots: { | ||
| default: 'Link text' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-base') | ||
| expect(link.classes()).toContain('leading-base') | ||
| }) | ||
| it('maps deprecated xs size to sm and shows warning', async () => { | ||
| const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| size: 'xs' | ||
| }, | ||
| slots: { | ||
| default: 'Link text' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| // Verify xs is mapped to sm classes | ||
| expect(link.classes()).toContain('text-sm') | ||
| expect(link.classes()).toContain('leading-xs') | ||
| expect(link.classes()).not.toContain('text-xs') | ||
| // Verify warning was shown | ||
| expect(consoleSpy).toHaveBeenCalledTimes(1) | ||
| const warningMessage = consoleSpy.mock.calls[0][0] as string | ||
| expect(warningMessage).toContain('[FzLink] The size prop value "xs" is deprecated') | ||
| expect(warningMessage).toContain('Please use "sm" instead') | ||
| consoleSpy.mockRestore() | ||
| }) | ||
| it('maps deprecated lg size to md and shows warning', async () => { | ||
| const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| size: 'lg' | ||
| }, | ||
| slots: { | ||
| default: 'Link text' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| // Verify lg is mapped to md classes | ||
| expect(link.classes()).toContain('text-base') | ||
| expect(link.classes()).toContain('leading-base') | ||
| expect(link.classes()).not.toContain('text-lg') | ||
| // Verify warning was shown | ||
| expect(consoleSpy).toHaveBeenCalledTimes(1) | ||
| const warningMessage = consoleSpy.mock.calls[0][0] as string | ||
| expect(warningMessage).toContain('[FzLink] The size prop value "lg" is deprecated') | ||
| expect(warningMessage).toContain('Please use "md" instead') | ||
| consoleSpy.mockRestore() | ||
| }) | ||
| }) | ||
| describe('Props: disabled', () => { | ||
| it('renders span with disabled classes', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('cursor-not-allowed') | ||
| expect(span.classes()).toContain('text-blue-200') | ||
| }) | ||
| it('applies default type disabled classes', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| disabled: true, | ||
| type: 'default' | ||
| }, | ||
| slots: { | ||
| default: 'Disabled default' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.classes()).toContain('text-blue-200') | ||
| }) | ||
| }) | ||
| describe('Props: external', () => { | ||
| it('renders anchor tag with href when external', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('href')).toBe('https://example.com') | ||
| }) | ||
| it('does not render router-link when external', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| // External links use <a> with href, not router-link | ||
| const link = wrapper.find('a') | ||
| expect(link.exists()).toBe(true) | ||
| expect(link.attributes('href')).toBe('https://example.com') | ||
| }) | ||
| it('uses correct href for external links', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| // Verify href attribute is set correctly | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('href')).toBe('https://example.com') | ||
| }) | ||
| }) | ||
| describe('Props: target', () => { | ||
| it('applies target attribute to anchor tag', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| target: '_blank' | ||
| }, | ||
| slots: { | ||
| default: 'Link with target' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('target')).toBe('_blank') | ||
| }) | ||
| it('applies target attribute to external link', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true, | ||
| target: '_blank' | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('target')).toBe('_blank') | ||
| }) | ||
| }) | ||
| describe('Props: replace', () => { | ||
| it('passes replace prop to router-link', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| replace: true | ||
| }, | ||
| slots: { | ||
| default: 'Replace link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| // router-link renders as <a>, verify component accepts replace prop | ||
| const link = wrapper.find('a') | ||
| expect(link.exists()).toBe(true) | ||
| // The replace prop is handled by router-link internally | ||
| expect(wrapper.props('replace')).toBe(true) | ||
| }) | ||
| }) | ||
| describe('Accessibility', () => { | ||
| it('should have proper ARIA attributes when disabled', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'Disabled link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const span = wrapper.find('span') | ||
| expect(span.exists()).toBe(true) | ||
| expect(span.attributes('aria-disabled')).toBe('true') | ||
| expect(span.attributes('role')).toBe('link') | ||
| expect(span.attributes('aria-label')).toBe('Link disabled') | ||
| }) | ||
| it('external link should have href attribute', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('href')).toBeDefined() | ||
| expect(link.attributes('href')).toBe('https://example.com') | ||
| }) | ||
| it('external link with target="_blank" should have rel="noopener noreferrer"', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true, | ||
| target: '_blank' | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('rel')).toBe('noopener noreferrer') | ||
| expect(link.attributes('target')).toBe('_blank') | ||
| }) | ||
| it('external link without target="_blank" should not have rel attribute', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true, | ||
| target: '_self' | ||
| }, | ||
| slots: { | ||
| default: 'External link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('rel')).toBeUndefined() | ||
| expect(link.attributes('target')).toBe('_self') | ||
| }) | ||
| }) | ||
| describe('RouteLocationRaw support', () => { | ||
| it('accepts string path for internal links', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'String path link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.exists()).toBe(true) | ||
| }) | ||
| it('accepts object with path for internal links', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: { path: '/example', query: { id: '123' } } | ||
| }, | ||
| slots: { | ||
| default: 'Object path link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.exists()).toBe(true) | ||
| // router-link handles the object internally | ||
| }) | ||
| it('accepts object with name for internal links', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: { name: 'route-name', params: { id: 123 } } | ||
| }, | ||
| slots: { | ||
| default: 'Named route link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.exists()).toBe(true) | ||
| // router-link handles the named route internally | ||
| }) | ||
| it('requires string URL for external links', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: 'https://example.com', | ||
| external: true | ||
| }, | ||
| slots: { | ||
| default: 'External string link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.attributes('href')).toBe('https://example.com') | ||
| // TypeScript enforces: external=true requires to to be string | ||
| // This test verifies runtime behavior with correct types | ||
| }) | ||
| }) | ||
| describe('Edge cases', () => { | ||
| it('handles default props correctly', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'Link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-base') // default size | ||
| expect(link.classes()).toContain('leading-base') // default size line-height | ||
| expect(link.classes()).toContain('text-blue-500') // default type | ||
| expect(link.classes()).toContain('hover:text-blue-600') // default hover | ||
| expect(link.classes()).toContain('hover:underline') // default hover underline | ||
| expect(link.classes()).not.toContain('underline') // default linkStyle (no underline by default) | ||
| }) | ||
| it('renders correctly with all props combined', async () => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| type: 'danger', | ||
| linkStyle: 'underline', | ||
| size: 'sm', | ||
| target: '_self' | ||
| }, | ||
| slots: { | ||
| default: 'Complete link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| await wrapper.vm.$nextTick() | ||
| const link = wrapper.find('a') | ||
| expect(link.classes()).toContain('text-sm') | ||
| expect(link.classes()).toContain('leading-xs') | ||
| expect(link.classes()).toContain('underline') | ||
| expect(link.classes()).toContain('text-semantic-error-200') | ||
| expect(link.classes()).toContain('hover:text-semantic-error-300') | ||
| expect(link.classes()).toContain('focus:text-semantic-error-300') | ||
| expect(link.classes()).toContain('focus:outline-none') | ||
| expect(link.classes()).toContain('focus:border-solid') | ||
| expect(link.classes()).toContain('focus:no-underline') | ||
| expect(link.classes()).toContain('focus:border-semantic-error-300') | ||
| expect(link.attributes('target')).toBe('_self') | ||
| }) | ||
| }) | ||
| }) | ||
+65
-42
@@ -1,62 +0,85 @@ | ||
| import { defineComponent as i, computed as l, resolveComponent as c, openBlock as a, createElementBlock as d, normalizeClass as r, renderSlot as o, createBlock as m, withCtx as g } from "vue"; | ||
| const k = ["href", "target"], v = /* @__PURE__ */ i({ | ||
| import { defineComponent as x, computed as a, resolveComponent as z, createElementBlock as u, createBlock as w, openBlock as r, normalizeClass as l, renderSlot as n, withCtx as C } from "vue"; | ||
| const D = ["aria-disabled"], S = ["href", "target", "rel"], _ = /* @__PURE__ */ x({ | ||
| __name: "FzLink", | ||
| props: { | ||
| to: {}, | ||
| replace: { type: Boolean, default: !1 }, | ||
| type: { default: "default" }, | ||
| linkStyle: { default: "default" }, | ||
| size: { default: "lg" }, | ||
| size: { default: "md" }, | ||
| disabled: { type: Boolean, default: !1 }, | ||
| target: {}, | ||
| external: { type: Boolean, default: !1 } | ||
| to: {}, | ||
| external: { type: Boolean, default: !1 }, | ||
| replace: { type: Boolean, default: !1 }, | ||
| target: {} | ||
| }, | ||
| setup(u) { | ||
| const t = u, s = l(() => [ | ||
| "border-1 border-transparent", | ||
| setup(d) { | ||
| const t = d, s = a(() => t.size === "xs" ? (console.warn( | ||
| '[FzLink] The size prop value "xs" is deprecated and will be removed in a future version. Please use "sm" instead. The component will automatically map "xs" to "sm" for now.' | ||
| ), "sm") : t.size === "lg" ? (console.warn( | ||
| '[FzLink] The size prop value "lg" is deprecated and will be removed in a future version. Please use "md" instead. The component will automatically map "lg" to "md" for now.' | ||
| ), "md") : t.size), o = a(() => [ | ||
| "border-1 border-transparent inline-block", | ||
| { | ||
| "text-xs": t.size === "xs", | ||
| "text-sm": t.size === "sm", | ||
| "text-md": t.size === "md", | ||
| "text-lg": t.size === "lg", | ||
| "text-sm leading-xs": s.value === "sm", | ||
| "text-base leading-base": s.value === "md", | ||
| underline: t.linkStyle === "underline" | ||
| } | ||
| ]), n = l(() => [ | ||
| ...s.value, | ||
| "hover:underline", | ||
| { | ||
| "text-blue-500 hover:text-blue-600 focus:text-blue-600 focus:border-blue-600": t.type === "default", | ||
| "text-semantic-error hover:text-red-600 focus:text-red-600 focus:border-red-600": t.type === "danger" | ||
| ]), c = (e) => e.type === "default" && e.linkStyle === "underline", f = (e) => e.type === "default" && e.linkStyle !== "underline", p = (e) => e.type === "danger" && e.linkStyle === "underline", m = (e) => e.type === "danger" && e.linkStyle !== "underline", b = (e) => e.type === "default" && e.disabled, k = (e) => e.type === "danger" && e.disabled, i = a(() => { | ||
| const e = [...o.value]; | ||
| switch (!0) { | ||
| case c(t): | ||
| e.push("text-blue-500", "hover:text-blue-600", "focus:text-blue-600"); | ||
| break; | ||
| case f(t): | ||
| e.push("text-blue-500", "hover:text-blue-600", "hover:underline", "focus:text-blue-600"); | ||
| break; | ||
| case p(t): | ||
| e.push("text-semantic-error-200", "hover:text-semantic-error-300", "focus:text-semantic-error-300"); | ||
| break; | ||
| case m(t): | ||
| e.push("text-semantic-error-200", "hover:text-semantic-error-300", "hover:underline", "focus:text-semantic-error-300"); | ||
| break; | ||
| } | ||
| ]), p = l(() => [ | ||
| ...s.value, | ||
| "cursor-not-allowed", | ||
| { | ||
| "text-red-200": t.type === "danger", | ||
| "text-blue-200": t.type === "default" | ||
| return e; | ||
| }), h = a(() => { | ||
| const e = [...o.value, "cursor-not-allowed"]; | ||
| switch (!0) { | ||
| case b(t): | ||
| e.push("text-blue-200"); | ||
| break; | ||
| case k(t): | ||
| e.push("text-semantic-error-100"); | ||
| break; | ||
| } | ||
| ]); | ||
| return (e, y) => { | ||
| const f = c("router-link"); | ||
| return e.disabled ? (a(), d("span", { | ||
| return e; | ||
| }), v = a(() => t.external ? t.to : ""), y = a(() => { | ||
| if (t.external && t.target === "_blank") | ||
| return "noopener noreferrer"; | ||
| }); | ||
| return (e, B) => { | ||
| const g = z("router-link"); | ||
| return e.disabled ? (r(), u("span", { | ||
| key: 0, | ||
| class: r(p.value) | ||
| class: l(h.value), | ||
| "aria-disabled": e.disabled ? "true" : "false", | ||
| role: "link", | ||
| "aria-label": "Link disabled" | ||
| }, [ | ||
| o(e.$slots, "default") | ||
| ], 2)) : e.external ? (a(), d("a", { | ||
| n(e.$slots, "default") | ||
| ], 10, D)) : e.external ? (r(), u("a", { | ||
| key: 1, | ||
| href: e.to.toString(), | ||
| class: r(n.value), | ||
| target: e.target | ||
| href: v.value, | ||
| class: l(i.value), | ||
| target: e.target, | ||
| rel: y.value | ||
| }, [ | ||
| o(e.$slots, "default") | ||
| ], 10, k)) : (a(), m(f, { | ||
| n(e.$slots, "default") | ||
| ], 10, S)) : (r(), w(g, { | ||
| key: 2, | ||
| to: e.to, | ||
| replace: e.replace, | ||
| class: r(n.value), | ||
| class: l(i.value), | ||
| target: e.target | ||
| }, { | ||
| default: g(() => [ | ||
| o(e.$slots, "default") | ||
| default: C(() => [ | ||
| n(e.$slots, "default") | ||
| ]), | ||
@@ -69,3 +92,3 @@ _: 3 | ||
| export { | ||
| v as FzLink | ||
| _ as FzLink | ||
| }; |
@@ -1,1 +0,1 @@ | ||
| (function(o,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(o=typeof globalThis<"u"?globalThis:o||self,e(o.FzLink={},o.Vue))})(this,function(o,e){"use strict";const s=["href","target"],a=e.defineComponent({__name:"FzLink",props:{to:{},replace:{type:Boolean,default:!1},type:{default:"default"},linkStyle:{default:"default"},size:{default:"lg"},disabled:{type:Boolean,default:!1},target:{},external:{type:Boolean,default:!1}},setup(d){const l=d,n=e.computed(()=>["border-1 border-transparent",{"text-xs":l.size==="xs","text-sm":l.size==="sm","text-md":l.size==="md","text-lg":l.size==="lg",underline:l.linkStyle==="underline"}]),r=e.computed(()=>[...n.value,"hover:underline",{"text-blue-500 hover:text-blue-600 focus:text-blue-600 focus:border-blue-600":l.type==="default","text-semantic-error hover:text-red-600 focus:text-red-600 focus:border-red-600":l.type==="danger"}]),i=e.computed(()=>[...n.value,"cursor-not-allowed",{"text-red-200":l.type==="danger","text-blue-200":l.type==="default"}]);return(t,p)=>{const f=e.resolveComponent("router-link");return t.disabled?(e.openBlock(),e.createElementBlock("span",{key:0,class:e.normalizeClass(i.value)},[e.renderSlot(t.$slots,"default")],2)):t.external?(e.openBlock(),e.createElementBlock("a",{key:1,href:t.to.toString(),class:e.normalizeClass(r.value),target:t.target},[e.renderSlot(t.$slots,"default")],10,s)):(e.openBlock(),e.createBlock(f,{key:2,to:t.to,replace:t.replace,class:e.normalizeClass(r.value),target:t.target},{default:e.withCtx(()=>[e.renderSlot(t.$slots,"default")]),_:3},8,["to","replace","class","target"]))}}});o.FzLink=a,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})}); | ||
| (function(l,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(l=typeof globalThis<"u"?globalThis:l||self,t(l.FzLink={},l.Vue))})(this,function(l,t){"use strict";const o=["aria-disabled"],i=["href","target","rel"],d=t.defineComponent({__name:"FzLink",props:{type:{default:"default"},linkStyle:{default:"default"},size:{default:"md"},disabled:{type:Boolean,default:!1},to:{},external:{type:Boolean,default:!1},replace:{type:Boolean,default:!1},target:{}},setup(u){const n=u,r=t.computed(()=>n.size==="xs"?(console.warn('[FzLink] The size prop value "xs" is deprecated and will be removed in a future version. Please use "sm" instead. The component will automatically map "xs" to "sm" for now.'),"sm"):n.size==="lg"?(console.warn('[FzLink] The size prop value "lg" is deprecated and will be removed in a future version. Please use "md" instead. The component will automatically map "lg" to "md" for now.'),"md"):n.size),a=t.computed(()=>["border-1 border-transparent inline-block",{"text-sm leading-xs":r.value==="sm","text-base leading-base":r.value==="md",underline:n.linkStyle==="underline"}]),c=e=>e.type==="default"&&e.linkStyle==="underline",f=e=>e.type==="default"&&e.linkStyle!=="underline",p=e=>e.type==="danger"&&e.linkStyle==="underline",m=e=>e.type==="danger"&&e.linkStyle!=="underline",b=e=>e.type==="default"&&e.disabled,k=e=>e.type==="danger"&&e.disabled,s=t.computed(()=>{const e=[...a.value];switch(!0){case c(n):e.push("text-blue-500","hover:text-blue-600","focus:text-blue-600");break;case f(n):e.push("text-blue-500","hover:text-blue-600","hover:underline","focus:text-blue-600");break;case p(n):e.push("text-semantic-error-200","hover:text-semantic-error-300","focus:text-semantic-error-300");break;case m(n):e.push("text-semantic-error-200","hover:text-semantic-error-300","hover:underline","focus:text-semantic-error-300");break}return e}),h=t.computed(()=>{const e=[...a.value,"cursor-not-allowed"];switch(!0){case b(n):e.push("text-blue-200");break;case k(n):e.push("text-semantic-error-100");break}return e}),y=t.computed(()=>n.external?n.to:""),g=t.computed(()=>{if(n.external&&n.target==="_blank")return"noopener noreferrer"});return(e,z)=>{const x=t.resolveComponent("router-link");return e.disabled?(t.openBlock(),t.createElementBlock("span",{key:0,class:t.normalizeClass(h.value),"aria-disabled":e.disabled?"true":"false",role:"link","aria-label":"Link disabled"},[t.renderSlot(e.$slots,"default")],10,o)):e.external?(t.openBlock(),t.createElementBlock("a",{key:1,href:y.value,class:t.normalizeClass(s.value),target:e.target,rel:g.value},[t.renderSlot(e.$slots,"default")],10,i)):(t.openBlock(),t.createBlock(x,{key:2,to:e.to,replace:e.replace,class:t.normalizeClass(s.value),target:e.target},{default:t.withCtx(()=>[t.renderSlot(e.$slots,"default")]),_:3},8,["to","replace","class","target"]))}}});l.FzLink=d,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}); |
@@ -1,45 +0,5 @@ | ||
| import { FzLinkProps } from './types'; | ||
| declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<FzLinkProps>, { | ||
| type: string; | ||
| linkStyle: string; | ||
| size: string; | ||
| disabled: boolean; | ||
| replace: boolean; | ||
| external: boolean; | ||
| }>, {}, unknown, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<FzLinkProps>, { | ||
| type: string; | ||
| linkStyle: string; | ||
| size: string; | ||
| disabled: boolean; | ||
| replace: boolean; | ||
| external: boolean; | ||
| }>>>, { | ||
| replace: boolean; | ||
| type: "default" | "danger"; | ||
| linkStyle: "default" | "underline"; | ||
| size: "xs" | "sm" | "md" | "lg"; | ||
| disabled: boolean; | ||
| external: boolean; | ||
| }, {}>, { | ||
| declare const _default: __VLS_WithTemplateSlots<import('vue').DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import('vue').PublicProps>, { | ||
| default?(_: {}): any; | ||
| }>; | ||
| export default _default; | ||
| type __VLS_NonUndefinedable<T> = T extends undefined ? never : T; | ||
| type __VLS_TypePropsToRuntimeProps<T> = { | ||
| [K in keyof T]-?: {} extends Pick<T, K> ? { | ||
| type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>; | ||
| } : { | ||
| type: import('vue').PropType<T[K]>; | ||
| required: true; | ||
| }; | ||
| }; | ||
| type __VLS_WithDefaults<P, D> = { | ||
| [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & { | ||
| default: D[K]; | ||
| }> : P[K]; | ||
| }; | ||
| type __VLS_Prettify<T> = { | ||
| [K in keyof T]: T[K]; | ||
| } & {}; | ||
| type __VLS_WithTemplateSlots<T, S> = T & { | ||
@@ -46,0 +6,0 @@ new (): { |
+95
-16
| import { RouteLocationRaw } from 'vue-router'; | ||
| type FzLinkProps = { | ||
| /** | ||
| * Base props shared between internal and external link variants. | ||
| */ | ||
| type FzLinkBaseProps = { | ||
| /** | ||
| * Route Location the link should navigate to when clicked on. | ||
| * Visual variant indicating link purpose. Affects color scheme. | ||
| * @default 'default' | ||
| */ | ||
| type?: 'default' | 'danger'; | ||
| /** | ||
| * Text decoration style. 'default' shows underline on hover, 'underline' always shows underline. | ||
| * @default 'default' | ||
| */ | ||
| linkStyle?: 'default' | 'underline'; | ||
| /** | ||
| * Text size affecting font size and line height. | ||
| * @default 'md' | ||
| * @deprecated 'xs' is deprecated and will be mapped to 'sm'. Use 'sm' instead. | ||
| * @deprecated 'lg' is deprecated and will be mapped to 'md'. Use 'md' instead. | ||
| */ | ||
| size?: 'xs' | 'sm' | 'md' | 'lg'; | ||
| /** | ||
| * Disables the link, rendering as non-interactive span with disabled styling. | ||
| * @default false | ||
| */ | ||
| disabled?: boolean; | ||
| }; | ||
| /** | ||
| * Props for internal links (using vue-router). | ||
| * | ||
| * When external is false or undefined, to accepts RouteLocationRaw | ||
| * (string path or object with name, params, query, etc.). | ||
| * | ||
| * @example | ||
| * <FzLink to="/dashboard">Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User</FzLink> | ||
| */ | ||
| export type FzLinkInternalProps = FzLinkBaseProps & { | ||
| /** | ||
| * Destination route. Accepts vue-router RouteLocationRaw: | ||
| * - String path: "/dashboard" | ||
| * - Object with name: { name: 'user', params: { id: 123 } } | ||
| * - Object with path: { path: '/search', query: { q: 'vue' } } | ||
| */ | ||
| to: RouteLocationRaw; | ||
| /** | ||
| * Calls `router.replace` instead of `router.push`. | ||
| * When false or undefined, link uses vue-router for internal navigation. | ||
| * @default false | ||
| */ | ||
| replace?: boolean; | ||
| external?: false; | ||
| /** | ||
| * The purpose of the link | ||
| * Uses router.replace instead of router.push for navigation. | ||
| * @default false | ||
| */ | ||
| type?: 'default' | 'danger'; | ||
| replace?: boolean; | ||
| /** | ||
| * The appearance of the link | ||
| * Target attribute for anchor tag (e.g., '_blank', '_self'). | ||
| * Can be used with router-link to open internal routes in new tab/window. | ||
| */ | ||
| linkStyle?: 'default' | 'underline'; | ||
| target?: string; | ||
| }; | ||
| /** | ||
| * Props for external links (using anchor tag). | ||
| * | ||
| * When external is true, to must be a string URL. | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external>External Site</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">Open in New Tab</FzLink> | ||
| */ | ||
| export type FzLinkExternalProps = FzLinkBaseProps & { | ||
| /** | ||
| * Size of the link | ||
| * External URL as string. Must be a full URL (e.g., "https://example.com"). | ||
| */ | ||
| size?: 'xs' | 'sm' | 'md' | 'lg'; | ||
| to: string; | ||
| /** | ||
| * Whether the link is disabled | ||
| * When true, link renders as anchor tag with href for external navigation. | ||
| */ | ||
| disabled?: boolean; | ||
| external: true; | ||
| /** | ||
| * Target of the link | ||
| * Target attribute for anchor tag (e.g., '_blank', '_self'). | ||
| */ | ||
| target?: string; | ||
| /** | ||
| * Whether the link is for an external page or not | ||
| * Replace is not applicable for external links. | ||
| */ | ||
| external?: boolean; | ||
| replace?: never; | ||
| }; | ||
| export { FzLinkProps }; | ||
| /** | ||
| * Props for the FzLink component. | ||
| * | ||
| * A flexible link component that supports both internal routing (via vue-router) | ||
| * and external navigation. Automatically renders as router-link for internal routes, | ||
| * anchor tag for external URLs, or span when disabled. | ||
| * | ||
| * TypeScript will enforce: | ||
| * - Internal links (external=false or undefined): to accepts RouteLocationRaw (string or object) | ||
| * - External links (external=true): to must be a string URL | ||
| * | ||
| * @example | ||
| * <FzLink to="/dashboard" size="md">Go to Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User Profile</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">External Site</FzLink> | ||
| */ | ||
| export type FzLinkProps = FzLinkInternalProps | FzLinkExternalProps; | ||
| export {}; |
+1
-1
| { | ||
| "name": "@fiscozen/link", | ||
| "version": "0.1.4", | ||
| "version": "1.0.0-next.0", | ||
| "description": "Design System Link component", | ||
@@ -5,0 +5,0 @@ "main": "src/index.ts", |
+179
-1
| # @fiscozen/link | ||
| Links are used as navigational elements. They navigate users to another location, such as a different site, resource or section within the same page. | ||
| Flexible link component supporting internal routing (vue-router) and external navigation. Automatically renders as router-link for internal routes, anchor tag for external URLs, or non-interactive span when disabled. | ||
| ## Features | ||
| - **Internal Routing**: Uses vue-router for SPA navigation with RouteLocationRaw support (string or object) | ||
| - **External Navigation**: Supports external URLs with anchor tags | ||
| - **Disabled State**: Renders as non-interactive span with disabled styling | ||
| - **Multiple Variants**: Default and danger types | ||
| - **Text Styles**: Default (underline on hover) or always underlined | ||
| - **Size Options**: sm, md | ||
| - **TypeScript Type Safety**: Discriminated union types enforce correct prop combinations | ||
| - **Full Accessibility**: ARIA support and keyboard navigation | ||
| - **Security**: Automatic rel="noopener noreferrer" for external links with target="_blank" | ||
| ## Installation | ||
| ```bash | ||
| npm install @fiscozen/link | ||
| ``` | ||
| ## Basic Usage | ||
| ### Internal Route (String Path) | ||
| ```vue | ||
| <script setup lang="ts"> | ||
| import { FzLink } from '@fiscozen/link' | ||
| </script> | ||
| <template> | ||
| <FzLink to="/dashboard" size="md">Go to Dashboard</FzLink> | ||
| </template> | ||
| ``` | ||
| ### Internal Route (Object with Name) | ||
| ```vue | ||
| <template> | ||
| <FzLink :to="{ name: 'user', params: { id: 123 }}"> | ||
| User Profile | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ### Internal Route (Object with Path and Query) | ||
| ```vue | ||
| <template> | ||
| <FzLink :to="{ path: '/search', query: { q: 'vue' }}"> | ||
| Search Results | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ### External Link | ||
| ```vue | ||
| <template> | ||
| <FzLink to="https://example.com" external target="_blank"> | ||
| External Site | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ## Props | ||
| | Prop | Type | Default | Description | | ||
| |------|------|---------|-------------| | ||
| | `to` | `RouteLocationRaw \| string` | - | Destination route or URL. Type depends on `external` prop: **Internal** (external=false or undefined): Accepts vue-router RouteLocationRaw (string path or object with name/path, params, query, etc.). **External** (external=true): Must be a string URL. | | ||
| | `type` | `'default' \| 'danger'` | `'default'` | Visual variant indicating link purpose. Affects color scheme. | | ||
| | `linkStyle` | `'default' \| 'underline'` | `'default'` | Text decoration style. 'default' shows underline on hover, 'underline' always shows underline. | | ||
| | `size` | `'sm' \| 'md'` | `'md'` | Text size affecting font size and line height. | | ||
| | `disabled` | `boolean` | `false` | Disables the link, rendering as non-interactive span with disabled styling. | | ||
| | `target` | `string` | - | Target attribute for anchor tag (e.g., '_blank', '_self'). Can be used with both internal (router-link) and external links. | | ||
| | `external` | `boolean` | `false` | When true, renders as anchor tag with href instead of router-link. Use for external URLs or when router navigation is not desired. | | ||
| | `replace` | `boolean` | `false` | Uses router.replace instead of router.push for navigation. Only applies to internal routes (when external is false). | | ||
| ## TypeScript Type Safety | ||
| The component uses discriminated union types to enforce correct prop combinations: | ||
| - **Internal links** (`external=false` or `undefined`): | ||
| - `to` accepts `RouteLocationRaw` (string path or object with name/path, params, query, etc.) | ||
| - `replace` can be used | ||
| - `target` can be used (opens internal route in new tab/window) | ||
| - **External links** (`external=true`): | ||
| - `to` must be a string URL | ||
| - `target` can be used | ||
| - `replace` cannot be used (not applicable for external links) | ||
| TypeScript will show errors if you try to use incompatible prop combinations. | ||
| ## Examples | ||
| ### Navigation Menu | ||
| ```vue | ||
| <template> | ||
| <nav> | ||
| <FzLink to="/dashboard" size="md">Dashboard</FzLink> | ||
| <FzLink to="/settings" size="md">Settings</FzLink> | ||
| <FzLink :to="{ name: 'profile', params: { id: userId }}" size="md"> | ||
| Profile | ||
| </FzLink> | ||
| </nav> | ||
| </template> | ||
| ``` | ||
| ### External Links with Security | ||
| ```vue | ||
| <template> | ||
| <FzLink to="https://example.com" external target="_blank"> | ||
| Visit Example Site | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| The component automatically adds `rel="noopener noreferrer"` for security when `target="_blank"` is used. | ||
| ### Disabled State | ||
| ```vue | ||
| <template> | ||
| <FzLink to="/premium" disabled> | ||
| Premium Feature (Requires Upgrade) | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ### Danger Link | ||
| ```vue | ||
| <template> | ||
| <FzLink to="/delete-account" type="danger" size="md"> | ||
| Delete Account | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ### Replace Navigation | ||
| ```vue | ||
| <template> | ||
| <FzLink to="/redirect" replace> | ||
| Redirect Without History | ||
| </FzLink> | ||
| </template> | ||
| ``` | ||
| ## Accessibility | ||
| FzLink is fully accessible and meets WCAG 2.1 AA standards: | ||
| - **Keyboard Navigation**: All links are keyboard accessible (Tab, Enter) | ||
| - **Screen Readers**: Proper ARIA attributes for disabled state | ||
| - **Focus Indicators**: Visible focus outline with proper contrast | ||
| - **Semantic HTML**: Uses router-link for internal routes, anchor for external | ||
| - **Disabled State**: Renders as span with aria-disabled, role="link", and aria-label | ||
| ### ARIA Attributes | ||
| - `aria-disabled`: Set to "true" when link is disabled (string value for Vue 3 compatibility) | ||
| - `role`: Set to "link" for disabled span to maintain semantic meaning | ||
| - `aria-label`: Provides accessible label for disabled links | ||
| - `rel`: Automatically adds "noopener noreferrer" for external links with target="_blank" | ||
| ## Security | ||
| External links with `target="_blank"` automatically include `rel="noopener noreferrer"` to: | ||
| - Prevent security vulnerabilities (window.opener access) | ||
| - Improve privacy (no referrer information sent) | ||
| ## Related Components | ||
| - **FzNavlink**: Navigation link with active state support | ||
| - **FzButton**: Button component for actions | ||
| - **FzRouterNavlink**: Router-aware navigation link |
+208
-34
@@ -1,15 +0,24 @@ | ||
| <template> | ||
| <span v-if="disabled" :class="spanClass"> | ||
| <slot></slot> | ||
| </span> | ||
| <a v-else-if="external" :href="to.toString()" :class="linkClass" :target> | ||
| <slot></slot> | ||
| </a> | ||
| <router-link v-else :to :replace :class="linkClass" :target> | ||
| <slot></slot> | ||
| </router-link> | ||
| </template> | ||
| <script setup lang="ts"> | ||
| import { computed } from 'vue' | ||
| /** | ||
| * FzLink Component | ||
| * | ||
| * Flexible link component supporting internal routing (vue-router) and external navigation. | ||
| * Automatically renders as router-link for internal routes, anchor tag for external URLs, | ||
| * or non-interactive span when disabled. Provides consistent styling and accessibility. | ||
| * | ||
| * TypeScript enforces correct prop types: | ||
| * - Internal links (external=false or undefined): to accepts RouteLocationRaw (string or object) | ||
| * - External links (external=true): to must be a string URL | ||
| * | ||
| * @component | ||
| * @example | ||
| * <FzLink to="/dashboard" size="md">Go to Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User Profile</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">External Site</FzLink> | ||
| */ | ||
| import { computed, watch } from 'vue' | ||
| import { FzLinkProps } from './types' | ||
@@ -20,3 +29,3 @@ | ||
| linkStyle: 'default', | ||
| size: 'lg', | ||
| size: 'md', | ||
| disabled: false, | ||
@@ -27,9 +36,73 @@ replace: false, | ||
| /** | ||
| * Deprecation warning for 'xs' size prop value. | ||
| * | ||
| * Watches for 'xs' size usage and logs warning once on mount or when size changes. | ||
| * Using watch with immediate:true ensures the warning only fires once per component instance. | ||
| */ | ||
| watch( | ||
| () => props.size === 'xs', | ||
| (isXs) => { | ||
| if (isXs) { | ||
| console.warn( | ||
| '[FzLink] The size prop value "xs" is deprecated and will be removed in a future version. ' + | ||
| 'Please use "sm" instead. The component will automatically map "xs" to "sm" for now.' | ||
| ) | ||
| } | ||
| }, | ||
| { immediate: true } | ||
| ) | ||
| /** | ||
| * Deprecation warning for 'lg' size prop value. | ||
| * | ||
| * Watches for 'lg' size usage and logs warning once on mount or when size changes. | ||
| * Using watch with immediate:true ensures the warning only fires once per component instance. | ||
| */ | ||
| watch( | ||
| () => props.size === 'lg', | ||
| (isLg) => { | ||
| if (isLg) { | ||
| console.warn( | ||
| '[FzLink] The size prop value "lg" is deprecated and will be removed in a future version. ' + | ||
| 'Please use "md" instead. The component will automatically map "lg" to "md" for now.' | ||
| ) | ||
| } | ||
| }, | ||
| { immediate: true } | ||
| ) | ||
| /** | ||
| * Normalizes deprecated size values to their replacements. | ||
| * | ||
| * Maps deprecated sizes to their replacements: | ||
| * - 'xs' → 'sm' | ||
| * - 'lg' → 'md' | ||
| * | ||
| * This ensures backward compatibility while encouraging migration to new values. | ||
| * Deprecation warnings are handled separately via watch hooks. | ||
| */ | ||
| const normalizedSize = computed(() => { | ||
| if (props.size === 'xs') { | ||
| return 'sm' | ||
| } | ||
| if (props.size === 'lg') { | ||
| return 'md' | ||
| } | ||
| return props.size as 'sm' | 'md' | ||
| }) | ||
| /** | ||
| * Base classes shared between link and disabled span states. | ||
| * | ||
| * Includes size-based text classes and conditional underline styling. | ||
| * Border classes provide consistent spacing for focus indicators. | ||
| */ | ||
| const commonClass = computed(() => [ | ||
| 'border-1 border-transparent inline-block', | ||
| { | ||
| 'text-xs': props.size === 'xs', | ||
| 'text-sm': props.size === 'sm', | ||
| 'text-md': props.size === 'md', | ||
| 'text-lg': props.size === 'lg', | ||
| 'text-sm leading-xs': normalizedSize.value === 'sm', | ||
| 'text-base leading-base': normalizedSize.value === 'md', | ||
| underline: props.linkStyle === 'underline' | ||
@@ -39,21 +112,122 @@ } | ||
| const linkClass = computed(() => [ | ||
| ...commonClass.value, | ||
| 'hover:underline', | ||
| { | ||
| 'text-blue-500 hover:text-blue-600 focus:text-blue-600 focus:border-blue-600': | ||
| props.type === 'default', | ||
| 'text-semantic-error hover:text-red-600 focus:text-red-600 focus:border-red-600': | ||
| props.type === 'danger' | ||
| /** | ||
| * Helper functions to identify UI states. | ||
| * | ||
| * These functions explicitly describe when each UI representation should be applied, | ||
| * making the component logic more declarative and maintainable. | ||
| */ | ||
| const isDefaultUnderline = (p: typeof props) => p.type === 'default' && p.linkStyle === 'underline' | ||
| const isDefaultNoUnderline = (p: typeof props) => p.type === 'default' && p.linkStyle !== 'underline' | ||
| const isDangerUnderline = (p: typeof props) => p.type === 'danger' && p.linkStyle === 'underline' | ||
| const isDangerNoUnderline = (p: typeof props) => p.type === 'danger' && p.linkStyle !== 'underline' | ||
| const isDefaultDisabled = (p: typeof props) => p.type === 'default' && p.disabled | ||
| const isDangerDisabled = (p: typeof props) => p.type === 'danger' && p.disabled | ||
| /** | ||
| * CSS classes for interactive link states (router-link and anchor). | ||
| */ | ||
| const linkClass = computed(() => { | ||
| const baseClasses = [...commonClass.value, 'focus:outline-none', 'focus:border-solid', 'focus:no-underline'] | ||
| switch (true) { | ||
| case isDefaultUnderline(props): | ||
| baseClasses.push('text-blue-500', 'hover:text-blue-600', 'focus:text-blue-600', 'focus:border-blue-600') | ||
| break | ||
| case isDefaultNoUnderline(props): | ||
| baseClasses.push('text-blue-500', 'hover:text-blue-600', 'hover:underline', 'focus:text-blue-600', 'focus:border-blue-600') | ||
| break | ||
| case isDangerUnderline(props): | ||
| baseClasses.push('text-semantic-error-200', 'hover:text-semantic-error-300', 'focus:text-semantic-error-300', 'focus:border-semantic-error-300') | ||
| break | ||
| case isDangerNoUnderline(props): | ||
| baseClasses.push('text-semantic-error-200', 'hover:text-semantic-error-300', 'hover:underline', 'focus:text-semantic-error-300', 'focus:border-semantic-error-300') | ||
| break | ||
| } | ||
| ]) | ||
| return baseClasses | ||
| }) | ||
| const spanClass = computed(() => [ | ||
| ...commonClass.value, | ||
| 'cursor-not-allowed', | ||
| { | ||
| 'text-red-200': props.type === 'danger', | ||
| 'text-blue-200': props.type === 'default' | ||
| /** | ||
| * CSS classes for disabled link state (rendered as span). | ||
| * | ||
| * Uses switch(true) pattern to explicitly map disabled UI states to their styling. | ||
| * Each case represents a distinct visual representation of the disabled link. | ||
| */ | ||
| const spanClass = computed(() => { | ||
| const baseClasses = [...commonClass.value, 'cursor-not-allowed'] | ||
| switch (true) { | ||
| case isDefaultDisabled(props): | ||
| // Default type disabled: blue-200, underline preserved if linkStyle is underline | ||
| baseClasses.push('text-blue-200') | ||
| break | ||
| case isDangerDisabled(props): | ||
| // Danger type disabled: semantic-error-100, underline preserved if linkStyle is underline | ||
| baseClasses.push('text-semantic-error-100') | ||
| break | ||
| } | ||
| ]) | ||
| return baseClasses | ||
| }) | ||
| /** | ||
| * Href value for external links. | ||
| * | ||
| * When external is true, TypeScript guarantees to is a string. | ||
| * This computed ensures type safety in the template. | ||
| */ | ||
| const externalHref = computed(() => { | ||
| if (props.external) { | ||
| // TypeScript narrows to to string when external is true | ||
| return props.to as string | ||
| } | ||
| return '' | ||
| }) | ||
| /** | ||
| * Rel attribute for external links with target="_blank". | ||
| * | ||
| * Adds security attributes (noopener noreferrer) when opening links in new tab | ||
| * to prevent security vulnerabilities and improve privacy. | ||
| */ | ||
| const externalRel = computed(() => { | ||
| if (props.external && props.target === '_blank') { | ||
| return 'noopener noreferrer' | ||
| } | ||
| return undefined | ||
| }) | ||
| </script> | ||
| <template> | ||
| <span | ||
| v-if="disabled" | ||
| :class="spanClass" | ||
| :aria-disabled="disabled ? 'true' : 'false'" | ||
| role="link" | ||
| aria-label="Link disabled" | ||
| > | ||
| <slot></slot> | ||
| </span> | ||
| <a | ||
| v-else-if="external" | ||
| :href="externalHref" | ||
| :class="linkClass" | ||
| :target="target" | ||
| :rel="externalRel" | ||
| > | ||
| <slot></slot> | ||
| </a> | ||
| <router-link | ||
| v-else | ||
| :to="to" | ||
| :replace="replace" | ||
| :class="linkClass" | ||
| :target="target" | ||
| > | ||
| <slot></slot> | ||
| </router-link> | ||
| </template> |
+102
-16
@@ -0,38 +1,124 @@ | ||
| /** | ||
| * Type definitions for the Fiscozen Link component library. | ||
| * | ||
| * @module @fiscozen/link/types | ||
| */ | ||
| import { RouteLocationRaw } from 'vue-router' | ||
| type FzLinkProps = { | ||
| /** | ||
| * Base props shared between internal and external link variants. | ||
| */ | ||
| type FzLinkBaseProps = { | ||
| /** | ||
| * Route Location the link should navigate to when clicked on. | ||
| * Visual variant indicating link purpose. Affects color scheme. | ||
| * @default 'default' | ||
| */ | ||
| type?: 'default' | 'danger' | ||
| /** | ||
| * Text decoration style. 'default' shows underline on hover, 'underline' always shows underline. | ||
| * @default 'default' | ||
| */ | ||
| linkStyle?: 'default' | 'underline' | ||
| /** | ||
| * Text size affecting font size and line height. | ||
| * @default 'md' | ||
| * @deprecated 'xs' is deprecated and will be mapped to 'sm'. Use 'sm' instead. | ||
| * @deprecated 'lg' is deprecated and will be mapped to 'md'. Use 'md' instead. | ||
| */ | ||
| size?: 'xs' | 'sm' | 'md' | 'lg' | ||
| /** | ||
| * Disables the link, rendering as non-interactive span with disabled styling. | ||
| * @default false | ||
| */ | ||
| disabled?: boolean | ||
| } | ||
| /** | ||
| * Props for internal links (using vue-router). | ||
| * | ||
| * When external is false or undefined, to accepts RouteLocationRaw | ||
| * (string path or object with name, params, query, etc.). | ||
| * | ||
| * @example | ||
| * <FzLink to="/dashboard">Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User</FzLink> | ||
| */ | ||
| export type FzLinkInternalProps = FzLinkBaseProps & { | ||
| /** | ||
| * Destination route. Accepts vue-router RouteLocationRaw: | ||
| * - String path: "/dashboard" | ||
| * - Object with name: { name: 'user', params: { id: 123 } } | ||
| * - Object with path: { path: '/search', query: { q: 'vue' } } | ||
| */ | ||
| to: RouteLocationRaw | ||
| /** | ||
| * Calls `router.replace` instead of `router.push`. | ||
| * When false or undefined, link uses vue-router for internal navigation. | ||
| * @default false | ||
| */ | ||
| replace?: boolean | ||
| external?: false | ||
| /** | ||
| * The purpose of the link | ||
| * Uses router.replace instead of router.push for navigation. | ||
| * @default false | ||
| */ | ||
| type?: 'default' | 'danger' | ||
| replace?: boolean | ||
| /** | ||
| * The appearance of the link | ||
| * Target attribute for anchor tag (e.g., '_blank', '_self'). | ||
| * Can be used with router-link to open internal routes in new tab/window. | ||
| */ | ||
| linkStyle?: 'default' | 'underline' | ||
| target?: string | ||
| } | ||
| /** | ||
| * Props for external links (using anchor tag). | ||
| * | ||
| * When external is true, to must be a string URL. | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external>External Site</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">Open in New Tab</FzLink> | ||
| */ | ||
| export type FzLinkExternalProps = FzLinkBaseProps & { | ||
| /** | ||
| * Size of the link | ||
| * External URL as string. Must be a full URL (e.g., "https://example.com"). | ||
| */ | ||
| size?: 'xs' | 'sm' | 'md' | 'lg' | ||
| to: string | ||
| /** | ||
| * Whether the link is disabled | ||
| * When true, link renders as anchor tag with href for external navigation. | ||
| */ | ||
| disabled?: boolean | ||
| external: true | ||
| /** | ||
| * Target of the link | ||
| * Target attribute for anchor tag (e.g., '_blank', '_self'). | ||
| */ | ||
| target?: string | ||
| /** | ||
| * Whether the link is for an external page or not | ||
| * Replace is not applicable for external links. | ||
| */ | ||
| external?: boolean | ||
| replace?: never | ||
| } | ||
| export { FzLinkProps } | ||
| /** | ||
| * Props for the FzLink component. | ||
| * | ||
| * A flexible link component that supports both internal routing (via vue-router) | ||
| * and external navigation. Automatically renders as router-link for internal routes, | ||
| * anchor tag for external URLs, or span when disabled. | ||
| * | ||
| * TypeScript will enforce: | ||
| * - Internal links (external=false or undefined): to accepts RouteLocationRaw (string or object) | ||
| * - External links (external=true): to must be a string URL | ||
| * | ||
| * @example | ||
| * <FzLink to="/dashboard" size="md">Go to Dashboard</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink :to="{ name: 'user', params: { id: 123 }}">User Profile</FzLink> | ||
| * | ||
| * @example | ||
| * <FzLink to="https://example.com" external target="_blank">External Site</FzLink> | ||
| */ | ||
| export type FzLinkProps = FzLinkInternalProps | FzLinkExternalProps |
Sorry, the diff of this file is not supported yet
| import { describe, it } from 'vitest' | ||
| import { mount } from '@vue/test-utils' | ||
| import FzLink from '../FzLink.vue' | ||
| import { createRouter, createWebHistory } from 'vue-router' | ||
| const router = createRouter({ | ||
| history: createWebHistory(), | ||
| routes: [{ name: '', path: '/example', component: () => {} }] | ||
| }) | ||
| describe.concurrent('FzLink', () => { | ||
| it('image matches snapshot', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.html()).toMatchSnapshot() | ||
| }) | ||
| it('should render link when not disabled', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.find('a').exists()).toBe(true) | ||
| }) | ||
| it('should render span when disabled', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example', | ||
| disabled: true | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.find('span').exists()).toBe(true) | ||
| }) | ||
| it('should render link href', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.find('a').attributes('href')).toBe('/example') | ||
| }) | ||
| it('should render text content', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.html()).toContain('This is a link') | ||
| }) | ||
| it('should render size', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| size: 'md', | ||
| to: '/example' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.find('a').classes()).toContain('text-md') | ||
| }) | ||
| it('should render target', async ({ expect }) => { | ||
| const wrapper = mount(FzLink, { | ||
| props: { | ||
| size: 'md', | ||
| to: '/example', | ||
| target: '_blank' | ||
| }, | ||
| slots: { | ||
| default: 'This is a link' | ||
| }, | ||
| global: { | ||
| plugins: [router] | ||
| } | ||
| }) | ||
| expect(wrapper.find('a').attributes().target).toBe('_blank') | ||
| }) | ||
| }) |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
160747
576.66%31
55%1823
368.64%182
5966.67%4
33.33%4
300%2
Infinity%