diff --git a/coverage/base.css b/coverage/base.css deleted file mode 100644 index f418035b..00000000 --- a/coverage/base.css +++ /dev/null @@ -1,224 +0,0 @@ -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; -} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js deleted file mode 100644 index cc121302..00000000 --- a/coverage/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* 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); diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json deleted file mode 100644 index 59d9ebd2..00000000 --- a/coverage/coverage-final.json +++ /dev/null @@ -1,6 +0,0 @@ -{"/root/GitHub/arbiter/src/cli.ts": {"path":"/root/GitHub/arbiter/src/cli.ts","all":true,"statementMap":{"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":36}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":26}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":43}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":30}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":35}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":7}},"11":{"start":{"line":12,"column":0},"end":{"line":12,"column":18}},"12":{"start":{"line":13,"column":0},"end":{"line":13,"column":79}},"13":{"start":{"line":14,"column":0},"end":{"line":14,"column":19}},"14":{"start":{"line":15,"column":0},"end":{"line":15,"column":69}},"15":{"start":{"line":16,"column":0},"end":{"line":16,"column":75}},"16":{"start":{"line":17,"column":0},"end":{"line":17,"column":88}},"17":{"start":{"line":18,"column":0},"end":{"line":18,"column":69}},"18":{"start":{"line":19,"column":0},"end":{"line":19,"column":61}},"19":{"start":{"line":20,"column":0},"end":{"line":20,"column":54}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":52}},"21":{"start":{"line":22,"column":0},"end":{"line":22,"column":23}},"23":{"start":{"line":24,"column":0},"end":{"line":24,"column":31}},"26":{"start":{"line":27,"column":0},"end":{"line":27,"column":14}},"27":{"start":{"line":28,"column":0},"end":{"line":28,"column":25}},"28":{"start":{"line":29,"column":0},"end":{"line":29,"column":36}},"29":{"start":{"line":30,"column":0},"end":{"line":30,"column":39}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":22}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":26}},"32":{"start":{"line":33,"column":0},"end":{"line":33,"column":21}},"33":{"start":{"line":34,"column":0},"end":{"line":34,"column":62}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":18}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":3}}},"s":{"2":0,"3":0,"4":0,"6":0,"8":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"23":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0},"branchMap":{"0":{"type":"branch","line":1,"loc":{"start":{"line":1,"column":1155},"end":{"line":36,"column":3}},"locations":[{"start":{"line":1,"column":1155},"end":{"line":36,"column":3}}]}},"b":{"0":[1]},"fnMap":{"0":{"name":"(empty-report)","decl":{"start":{"line":1,"column":1155},"end":{"line":36,"column":3}},"loc":{"start":{"line":1,"column":1155},"end":{"line":36,"column":3}},"line":1}},"f":{"0":1}} -,"/root/GitHub/arbiter/src/server.ts": {"path":"/root/GitHub/arbiter/src/server.ts","all":true,"statementMap":{"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":28}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":37}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":33}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":46}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":35}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":55}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":82}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":35}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":26}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":114}},"22":{"start":{"line":23,"column":0},"end":{"line":23,"column":44}},"25":{"start":{"line":26,"column":0},"end":{"line":26,"column":30}},"26":{"start":{"line":27,"column":0},"end":{"line":27,"column":29}},"29":{"start":{"line":30,"column":0},"end":{"line":30,"column":45}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":23}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":18}},"32":{"start":{"line":33,"column":0},"end":{"line":33,"column":29}},"33":{"start":{"line":34,"column":0},"end":{"line":34,"column":27}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":14}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":42}},"36":{"start":{"line":37,"column":0},"end":{"line":37,"column":6}},"37":{"start":{"line":38,"column":0},"end":{"line":38,"column":22}},"38":{"start":{"line":39,"column":0},"end":{"line":39,"column":31}},"39":{"start":{"line":40,"column":0},"end":{"line":40,"column":6}},"40":{"start":{"line":41,"column":0},"end":{"line":41,"column":5}},"43":{"start":{"line":44,"column":0},"end":{"line":44,"column":30}},"44":{"start":{"line":45,"column":0},"end":{"line":45,"column":39}},"45":{"start":{"line":46,"column":0},"end":{"line":46,"column":5}},"47":{"start":{"line":48,"column":0},"end":{"line":48,"column":48}},"49":{"start":{"line":50,"column":0},"end":{"line":50,"column":57}},"50":{"start":{"line":51,"column":0},"end":{"line":51,"column":5}},"53":{"start":{"line":54,"column":0},"end":{"line":54,"column":24}},"54":{"start":{"line":55,"column":0},"end":{"line":55,"column":32}},"55":{"start":{"line":56,"column":0},"end":{"line":56,"column":31}},"56":{"start":{"line":57,"column":0},"end":{"line":57,"column":3}},"57":{"start":{"line":58,"column":0},"end":{"line":58,"column":28}},"58":{"start":{"line":59,"column":0},"end":{"line":59,"column":34}},"59":{"start":{"line":60,"column":0},"end":{"line":60,"column":27}},"60":{"start":{"line":61,"column":0},"end":{"line":61,"column":33}},"63":{"start":{"line":64,"column":0},"end":{"line":64,"column":46}},"64":{"start":{"line":65,"column":0},"end":{"line":65,"column":47}},"65":{"start":{"line":66,"column":0},"end":{"line":66,"column":19}},"92":{"start":{"line":93,"column":0},"end":{"line":93,"column":7}},"93":{"start":{"line":94,"column":0},"end":{"line":94,"column":5}},"94":{"start":{"line":95,"column":0},"end":{"line":95,"column":48}},"95":{"start":{"line":96,"column":0},"end":{"line":96,"column":49}},"96":{"start":{"line":97,"column":0},"end":{"line":97,"column":5}},"97":{"start":{"line":98,"column":0},"end":{"line":98,"column":48}},"98":{"start":{"line":99,"column":0},"end":{"line":99,"column":55}},"99":{"start":{"line":100,"column":0},"end":{"line":100,"column":5}},"100":{"start":{"line":101,"column":0},"end":{"line":101,"column":39}},"101":{"start":{"line":102,"column":0},"end":{"line":102,"column":46}},"102":{"start":{"line":103,"column":0},"end":{"line":103,"column":5}},"105":{"start":{"line":106,"column":0},"end":{"line":106,"column":43}},"106":{"start":{"line":107,"column":0},"end":{"line":107,"column":25}},"107":{"start":{"line":108,"column":0},"end":{"line":108,"column":26}},"110":{"start":{"line":111,"column":0},"end":{"line":111,"column":60}},"111":{"start":{"line":112,"column":0},"end":{"line":112,"column":11}},"112":{"start":{"line":113,"column":0},"end":{"line":113,"column":41}},"113":{"start":{"line":114,"column":0},"end":{"line":114,"column":19}},"115":{"start":{"line":116,"column":0},"end":{"line":116,"column":41}},"116":{"start":{"line":117,"column":0},"end":{"line":117,"column":7}},"117":{"start":{"line":118,"column":0},"end":{"line":118,"column":5}},"119":{"start":{"line":120,"column":0},"end":{"line":120,"column":9}},"121":{"start":{"line":122,"column":0},"end":{"line":122,"column":60}},"123":{"start":{"line":124,"column":0},"end":{"line":124,"column":45}},"124":{"start":{"line":125,"column":0},"end":{"line":125,"column":56}},"125":{"start":{"line":126,"column":0},"end":{"line":126,"column":50}},"126":{"start":{"line":127,"column":0},"end":{"line":127,"column":9}},"128":{"start":{"line":129,"column":0},"end":{"line":129,"column":58}},"129":{"start":{"line":130,"column":0},"end":{"line":130,"column":29}},"130":{"start":{"line":131,"column":0},"end":{"line":131,"column":30}},"131":{"start":{"line":132,"column":0},"end":{"line":132,"column":77}},"132":{"start":{"line":133,"column":0},"end":{"line":133,"column":65}},"133":{"start":{"line":134,"column":0},"end":{"line":134,"column":32}},"134":{"start":{"line":135,"column":0},"end":{"line":135,"column":42}},"135":{"start":{"line":136,"column":0},"end":{"line":136,"column":89}},"136":{"start":{"line":137,"column":0},"end":{"line":137,"column":12}},"137":{"start":{"line":138,"column":0},"end":{"line":138,"column":11}},"138":{"start":{"line":139,"column":0},"end":{"line":139,"column":90}},"139":{"start":{"line":140,"column":0},"end":{"line":140,"column":9}},"142":{"start":{"line":143,"column":0},"end":{"line":143,"column":45}},"145":{"start":{"line":146,"column":0},"end":{"line":146,"column":69}},"146":{"start":{"line":147,"column":0},"end":{"line":147,"column":53}},"147":{"start":{"line":148,"column":0},"end":{"line":148,"column":45}},"148":{"start":{"line":149,"column":0},"end":{"line":149,"column":14}},"149":{"start":{"line":150,"column":0},"end":{"line":150,"column":45}},"150":{"start":{"line":151,"column":0},"end":{"line":151,"column":7}},"153":{"start":{"line":154,"column":0},"end":{"line":154,"column":34}},"154":{"start":{"line":155,"column":0},"end":{"line":155,"column":19}},"155":{"start":{"line":156,"column":0},"end":{"line":156,"column":35}},"156":{"start":{"line":157,"column":0},"end":{"line":157,"column":9}},"157":{"start":{"line":158,"column":0},"end":{"line":158,"column":69}},"158":{"start":{"line":159,"column":0},"end":{"line":159,"column":28}},"159":{"start":{"line":160,"column":0},"end":{"line":160,"column":74}},"160":{"start":{"line":161,"column":0},"end":{"line":161,"column":69}},"161":{"start":{"line":162,"column":0},"end":{"line":162,"column":10}},"162":{"start":{"line":163,"column":0},"end":{"line":163,"column":9}},"163":{"start":{"line":164,"column":0},"end":{"line":164,"column":34}},"164":{"start":{"line":165,"column":0},"end":{"line":165,"column":29}},"165":{"start":{"line":166,"column":0},"end":{"line":166,"column":82}},"166":{"start":{"line":167,"column":0},"end":{"line":167,"column":65}},"167":{"start":{"line":168,"column":0},"end":{"line":168,"column":9}},"168":{"start":{"line":169,"column":0},"end":{"line":169,"column":8}},"171":{"start":{"line":172,"column":0},"end":{"line":172,"column":57}},"172":{"start":{"line":173,"column":0},"end":{"line":173,"column":32}},"173":{"start":{"line":174,"column":0},"end":{"line":174,"column":63}},"174":{"start":{"line":175,"column":0},"end":{"line":175,"column":9}},"175":{"start":{"line":176,"column":0},"end":{"line":176,"column":26}},"176":{"start":{"line":177,"column":0},"end":{"line":177,"column":52}},"177":{"start":{"line":178,"column":0},"end":{"line":178,"column":75}},"178":{"start":{"line":179,"column":0},"end":{"line":179,"column":5}},"179":{"start":{"line":180,"column":0},"end":{"line":180,"column":5}},"182":{"start":{"line":183,"column":0},"end":{"line":183,"column":23}},"183":{"start":{"line":184,"column":0},"end":{"line":184,"column":40}},"184":{"start":{"line":185,"column":0},"end":{"line":185,"column":70}},"185":{"start":{"line":186,"column":0},"end":{"line":186,"column":7}},"186":{"start":{"line":187,"column":0},"end":{"line":187,"column":3}},"189":{"start":{"line":190,"column":0},"end":{"line":190,"column":66}},"190":{"start":{"line":191,"column":0},"end":{"line":191,"column":37}},"191":{"start":{"line":192,"column":0},"end":{"line":192,"column":35}},"192":{"start":{"line":193,"column":0},"end":{"line":193,"column":30}},"193":{"start":{"line":194,"column":0},"end":{"line":194,"column":25}},"194":{"start":{"line":195,"column":0},"end":{"line":195,"column":10}},"195":{"start":{"line":196,"column":0},"end":{"line":196,"column":34}},"196":{"start":{"line":197,"column":0},"end":{"line":197,"column":25}},"197":{"start":{"line":198,"column":0},"end":{"line":198,"column":24}},"198":{"start":{"line":199,"column":0},"end":{"line":199,"column":10}},"199":{"start":{"line":200,"column":0},"end":{"line":200,"column":22}},"200":{"start":{"line":201,"column":0},"end":{"line":201,"column":7}},"201":{"start":{"line":202,"column":0},"end":{"line":202,"column":3}},"204":{"start":{"line":205,"column":0},"end":{"line":205,"column":72}},"205":{"start":{"line":206,"column":0},"end":{"line":206,"column":25}},"206":{"start":{"line":207,"column":0},"end":{"line":207,"column":44}},"207":{"start":{"line":208,"column":0},"end":{"line":208,"column":13}},"208":{"start":{"line":209,"column":0},"end":{"line":209,"column":5}},"209":{"start":{"line":210,"column":0},"end":{"line":210,"column":16}},"210":{"start":{"line":211,"column":0},"end":{"line":211,"column":3}},"213":{"start":{"line":214,"column":0},"end":{"line":214,"column":72}},"214":{"start":{"line":215,"column":0},"end":{"line":215,"column":70}},"216":{"start":{"line":217,"column":0},"end":{"line":217,"column":49}},"217":{"start":{"line":218,"column":0},"end":{"line":218,"column":111}},"218":{"start":{"line":219,"column":0},"end":{"line":219,"column":3}},"219":{"start":{"line":220,"column":0},"end":{"line":220,"column":47}},"220":{"start":{"line":221,"column":0},"end":{"line":221,"column":109}},"221":{"start":{"line":222,"column":0},"end":{"line":222,"column":3}},"223":{"start":{"line":224,"column":0},"end":{"line":224,"column":84}},"224":{"start":{"line":225,"column":0},"end":{"line":225,"column":69}},"225":{"start":{"line":226,"column":0},"end":{"line":226,"column":91}},"227":{"start":{"line":228,"column":0},"end":{"line":228,"column":56}},"228":{"start":{"line":229,"column":0},"end":{"line":229,"column":9}},"229":{"start":{"line":230,"column":0},"end":{"line":230,"column":84}},"230":{"start":{"line":231,"column":0},"end":{"line":231,"column":51}},"231":{"start":{"line":232,"column":0},"end":{"line":232,"column":36}},"232":{"start":{"line":233,"column":0},"end":{"line":233,"column":55}},"233":{"start":{"line":234,"column":0},"end":{"line":234,"column":78}},"234":{"start":{"line":235,"column":0},"end":{"line":235,"column":9}},"236":{"start":{"line":237,"column":0},"end":{"line":237,"column":53}},"237":{"start":{"line":238,"column":0},"end":{"line":238,"column":39}},"238":{"start":{"line":239,"column":0},"end":{"line":239,"column":46}},"241":{"start":{"line":242,"column":0},"end":{"line":242,"column":62}},"242":{"start":{"line":243,"column":0},"end":{"line":243,"column":34}},"243":{"start":{"line":244,"column":0},"end":{"line":244,"column":7}},"246":{"start":{"line":247,"column":0},"end":{"line":247,"column":26}},"247":{"start":{"line":248,"column":0},"end":{"line":248,"column":49}},"248":{"start":{"line":249,"column":0},"end":{"line":249,"column":22}},"249":{"start":{"line":250,"column":0},"end":{"line":250,"column":54}},"250":{"start":{"line":251,"column":0},"end":{"line":251,"column":26}},"251":{"start":{"line":252,"column":0},"end":{"line":252,"column":27}},"252":{"start":{"line":253,"column":0},"end":{"line":253,"column":9}},"253":{"start":{"line":254,"column":0},"end":{"line":254,"column":18}},"254":{"start":{"line":255,"column":0},"end":{"line":255,"column":14}},"255":{"start":{"line":256,"column":0},"end":{"line":256,"column":18}},"256":{"start":{"line":257,"column":0},"end":{"line":257,"column":7}},"257":{"start":{"line":258,"column":0},"end":{"line":258,"column":26}},"258":{"start":{"line":259,"column":0},"end":{"line":259,"column":52}},"259":{"start":{"line":260,"column":0},"end":{"line":260,"column":27}},"260":{"start":{"line":261,"column":0},"end":{"line":261,"column":80}},"261":{"start":{"line":262,"column":0},"end":{"line":262,"column":5}},"262":{"start":{"line":263,"column":0},"end":{"line":263,"column":5}},"264":{"start":{"line":265,"column":0},"end":{"line":265,"column":55}},"265":{"start":{"line":266,"column":0},"end":{"line":266,"column":9}},"266":{"start":{"line":267,"column":0},"end":{"line":267,"column":83}},"267":{"start":{"line":268,"column":0},"end":{"line":268,"column":51}},"268":{"start":{"line":269,"column":0},"end":{"line":269,"column":36}},"269":{"start":{"line":270,"column":0},"end":{"line":270,"column":55}},"270":{"start":{"line":271,"column":0},"end":{"line":271,"column":78}},"271":{"start":{"line":272,"column":0},"end":{"line":272,"column":9}},"273":{"start":{"line":274,"column":0},"end":{"line":274,"column":52}},"274":{"start":{"line":275,"column":0},"end":{"line":275,"column":39}},"275":{"start":{"line":276,"column":0},"end":{"line":276,"column":46}},"277":{"start":{"line":278,"column":0},"end":{"line":278,"column":62}},"278":{"start":{"line":279,"column":0},"end":{"line":279,"column":34}},"279":{"start":{"line":280,"column":0},"end":{"line":280,"column":7}},"281":{"start":{"line":282,"column":0},"end":{"line":282,"column":26}},"282":{"start":{"line":283,"column":0},"end":{"line":283,"column":49}},"283":{"start":{"line":284,"column":0},"end":{"line":284,"column":22}},"284":{"start":{"line":285,"column":0},"end":{"line":285,"column":54}},"285":{"start":{"line":286,"column":0},"end":{"line":286,"column":26}},"286":{"start":{"line":287,"column":0},"end":{"line":287,"column":27}},"287":{"start":{"line":288,"column":0},"end":{"line":288,"column":9}},"288":{"start":{"line":289,"column":0},"end":{"line":289,"column":7}},"289":{"start":{"line":290,"column":0},"end":{"line":290,"column":16}},"290":{"start":{"line":291,"column":0},"end":{"line":291,"column":26}},"291":{"start":{"line":292,"column":0},"end":{"line":292,"column":60}},"292":{"start":{"line":293,"column":0},"end":{"line":293,"column":27}},"293":{"start":{"line":294,"column":0},"end":{"line":294,"column":88}},"294":{"start":{"line":295,"column":0},"end":{"line":295,"column":5}},"295":{"start":{"line":296,"column":0},"end":{"line":296,"column":5}},"297":{"start":{"line":298,"column":0},"end":{"line":298,"column":48}},"298":{"start":{"line":299,"column":0},"end":{"line":299,"column":38}},"299":{"start":{"line":300,"column":0},"end":{"line":300,"column":61}},"300":{"start":{"line":301,"column":0},"end":{"line":301,"column":87}},"301":{"start":{"line":302,"column":0},"end":{"line":302,"column":16}},"302":{"start":{"line":303,"column":0},"end":{"line":303,"column":7}},"303":{"start":{"line":304,"column":0},"end":{"line":304,"column":5}},"305":{"start":{"line":306,"column":0},"end":{"line":306,"column":48}},"306":{"start":{"line":307,"column":0},"end":{"line":307,"column":37}},"307":{"start":{"line":308,"column":0},"end":{"line":308,"column":59}},"308":{"start":{"line":309,"column":0},"end":{"line":309,"column":94}},"309":{"start":{"line":310,"column":0},"end":{"line":310,"column":16}},"310":{"start":{"line":311,"column":0},"end":{"line":311,"column":7}},"311":{"start":{"line":312,"column":0},"end":{"line":312,"column":5}},"314":{"start":{"line":315,"column":0},"end":{"line":315,"column":60}},"315":{"start":{"line":316,"column":0},"end":{"line":316,"column":50}},"316":{"start":{"line":317,"column":0},"end":{"line":317,"column":75}},"317":{"start":{"line":318,"column":0},"end":{"line":318,"column":57}},"318":{"start":{"line":319,"column":0},"end":{"line":319,"column":51}},"319":{"start":{"line":320,"column":0},"end":{"line":320,"column":89}},"320":{"start":{"line":321,"column":0},"end":{"line":321,"column":45}},"321":{"start":{"line":322,"column":0},"end":{"line":322,"column":85}},"322":{"start":{"line":323,"column":0},"end":{"line":323,"column":96}},"323":{"start":{"line":324,"column":0},"end":{"line":324,"column":96}},"324":{"start":{"line":325,"column":0},"end":{"line":325,"column":59}},"326":{"start":{"line":327,"column":0},"end":{"line":327,"column":37}},"327":{"start":{"line":328,"column":0},"end":{"line":328,"column":1}}},"s":{"1":0,"2":0,"3":0,"4":0,"5":0,"7":0,"8":0,"9":0,"10":0,"20":0,"22":0,"25":0,"26":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"43":0,"44":0,"45":0,"47":0,"49":0,"50":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"63":0,"64":0,"65":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"105":0,"106":0,"107":0,"110":0,"111":0,"112":0,"113":0,"115":0,"116":0,"117":0,"119":0,"121":0,"123":0,"124":0,"125":0,"126":0,"128":0,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":0,"136":0,"137":0,"138":0,"139":0,"142":0,"145":0,"146":0,"147":0,"148":0,"149":0,"150":0,"153":0,"154":0,"155":0,"156":0,"157":0,"158":0,"159":0,"160":0,"161":0,"162":0,"163":0,"164":0,"165":0,"166":0,"167":0,"168":0,"171":0,"172":0,"173":0,"174":0,"175":0,"176":0,"177":0,"178":0,"179":0,"182":0,"183":0,"184":0,"185":0,"186":0,"189":0,"190":0,"191":0,"192":0,"193":0,"194":0,"195":0,"196":0,"197":0,"198":0,"199":0,"200":0,"201":0,"204":0,"205":0,"206":0,"207":0,"208":0,"209":0,"210":0,"213":0,"214":0,"216":0,"217":0,"218":0,"219":0,"220":0,"221":0,"223":0,"224":0,"225":0,"227":0,"228":0,"229":0,"230":0,"231":0,"232":0,"233":0,"234":0,"236":0,"237":0,"238":0,"241":0,"242":0,"243":0,"246":0,"247":0,"248":0,"249":0,"250":0,"251":0,"252":0,"253":0,"254":0,"255":0,"256":0,"257":0,"258":0,"259":0,"260":0,"261":0,"262":0,"264":0,"265":0,"266":0,"267":0,"268":0,"269":0,"270":0,"271":0,"273":0,"274":0,"275":0,"277":0,"278":0,"279":0,"281":0,"282":0,"283":0,"284":0,"285":0,"286":0,"287":0,"288":0,"289":0,"290":0,"291":0,"292":0,"293":0,"294":0,"295":0,"297":0,"298":0,"299":0,"300":0,"301":0,"302":0,"303":0,"305":0,"306":0,"307":0,"308":0,"309":0,"310":0,"311":0,"314":0,"315":0,"316":0,"317":0,"318":0,"319":0,"320":0,"321":0,"322":0,"323":0,"324":0,"326":0,"327":0},"branchMap":{"0":{"type":"branch","line":1,"loc":{"start":{"line":1,"column":43},"end":{"line":328,"column":-14}},"locations":[{"start":{"line":1,"column":43},"end":{"line":328,"column":-14}}]}},"b":{"0":[1]},"fnMap":{"0":{"name":"(empty-report)","decl":{"start":{"line":1,"column":43},"end":{"line":328,"column":-14}},"loc":{"start":{"line":1,"column":43},"end":{"line":328,"column":-14}},"line":1}},"f":{"0":1}} -,"/root/GitHub/arbiter/src/middleware/apiDocGenerator.ts": {"path":"/root/GitHub/arbiter/src/middleware/apiDocGenerator.ts","all":true,"statementMap":{"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":56}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":81}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":15}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":30}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":15}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":31}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":5}},"11":{"start":{"line":12,"column":0},"end":{"line":12,"column":65}},"12":{"start":{"line":13,"column":0},"end":{"line":13,"column":49}},"13":{"start":{"line":14,"column":0},"end":{"line":14,"column":70}},"14":{"start":{"line":15,"column":0},"end":{"line":15,"column":6}},"15":{"start":{"line":16,"column":0},"end":{"line":16,"column":5}},"16":{"start":{"line":17,"column":0},"end":{"line":17,"column":27}},"17":{"start":{"line":18,"column":0},"end":{"line":18,"column":57}},"18":{"start":{"line":19,"column":0},"end":{"line":19,"column":75}},"19":{"start":{"line":20,"column":0},"end":{"line":20,"column":5}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":4}},"21":{"start":{"line":22,"column":0},"end":{"line":22,"column":2}}},"s":{"1":0,"3":0,"4":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0},"branchMap":{"0":{"type":"branch","line":1,"loc":{"start":{"line":1,"column":692},"end":{"line":22,"column":2}},"locations":[{"start":{"line":1,"column":692},"end":{"line":22,"column":2}}]}},"b":{"0":[1]},"fnMap":{"0":{"name":"(empty-report)","decl":{"start":{"line":1,"column":692},"end":{"line":22,"column":2}},"loc":{"start":{"line":1,"column":692},"end":{"line":22,"column":2}},"line":1}},"f":{"0":1}} -,"/root/GitHub/arbiter/src/middleware/harRecorder.ts": {"path":"/root/GitHub/arbiter/src/middleware/harRecorder.ts","all":false,"statementMap":{"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":56}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":59}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":31}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":23}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":58}},"36":{"start":{"line":37,"column":0},"end":{"line":37,"column":9}},"37":{"start":{"line":38,"column":0},"end":{"line":38,"column":39}},"38":{"start":{"line":39,"column":0},"end":{"line":39,"column":17}},"40":{"start":{"line":41,"column":0},"end":{"line":41,"column":39}},"41":{"start":{"line":42,"column":0},"end":{"line":42,"column":5}},"42":{"start":{"line":43,"column":0},"end":{"line":43,"column":3}},"45":{"start":{"line":46,"column":0},"end":{"line":46,"column":33}},"46":{"start":{"line":47,"column":0},"end":{"line":47,"column":49}},"47":{"start":{"line":48,"column":0},"end":{"line":48,"column":58}},"48":{"start":{"line":49,"column":0},"end":{"line":49,"column":29}},"49":{"start":{"line":50,"column":0},"end":{"line":50,"column":3}},"52":{"start":{"line":53,"column":0},"end":{"line":53,"column":52}},"53":{"start":{"line":54,"column":0},"end":{"line":54,"column":60}},"54":{"start":{"line":55,"column":0},"end":{"line":55,"column":36}},"55":{"start":{"line":56,"column":0},"end":{"line":56,"column":34}},"56":{"start":{"line":57,"column":0},"end":{"line":57,"column":5}},"57":{"start":{"line":58,"column":0},"end":{"line":58,"column":5}},"60":{"start":{"line":61,"column":0},"end":{"line":61,"column":15}},"63":{"start":{"line":64,"column":0},"end":{"line":64,"column":46}},"66":{"start":{"line":67,"column":0},"end":{"line":67,"column":24}},"67":{"start":{"line":68,"column":0},"end":{"line":68,"column":7}},"68":{"start":{"line":69,"column":0},"end":{"line":69,"column":46}},"69":{"start":{"line":70,"column":0},"end":{"line":70,"column":15}},"70":{"start":{"line":71,"column":0},"end":{"line":71,"column":46}},"71":{"start":{"line":72,"column":0},"end":{"line":72,"column":3}},"74":{"start":{"line":75,"column":0},"end":{"line":75,"column":30}},"75":{"start":{"line":76,"column":0},"end":{"line":76,"column":15}},"76":{"start":{"line":77,"column":0},"end":{"line":77,"column":31}},"77":{"start":{"line":78,"column":0},"end":{"line":78,"column":5}},"78":{"start":{"line":79,"column":0},"end":{"line":79,"column":25}},"79":{"start":{"line":80,"column":0},"end":{"line":80,"column":24}},"80":{"start":{"line":81,"column":0},"end":{"line":81,"column":70}},"81":{"start":{"line":82,"column":0},"end":{"line":82,"column":29}},"82":{"start":{"line":83,"column":0},"end":{"line":83,"column":6}},"83":{"start":{"line":84,"column":0},"end":{"line":84,"column":5}},"84":{"start":{"line":85,"column":0},"end":{"line":85,"column":27}},"85":{"start":{"line":86,"column":0},"end":{"line":86,"column":25}},"86":{"start":{"line":87,"column":0},"end":{"line":87,"column":75}},"87":{"start":{"line":88,"column":0},"end":{"line":88,"column":58}},"88":{"start":{"line":89,"column":0},"end":{"line":89,"column":5}},"89":{"start":{"line":90,"column":0},"end":{"line":90,"column":4}},"92":{"start":{"line":93,"column":0},"end":{"line":93,"column":43}},"93":{"start":{"line":94,"column":0},"end":{"line":94,"column":1}}},"s":{"1":1,"30":4,"31":4,"34":4,"35":4,"36":0,"37":0,"38":0,"40":0,"41":0,"42":0,"45":4,"46":4,"47":4,"48":2,"49":2,"52":4,"53":4,"54":8,"55":8,"56":8,"57":4,"60":4,"63":4,"66":4,"67":4,"68":4,"69":4,"70":0,"71":0,"74":4,"75":4,"76":4,"77":4,"78":4,"79":4,"80":4,"81":4,"82":4,"83":4,"84":4,"85":4,"86":4,"87":4,"88":4,"89":4,"92":4,"93":4},"branchMap":{"0":{"type":"branch","line":31,"loc":{"start":{"line":31,"column":0},"end":{"line":94,"column":1}},"locations":[{"start":{"line":31,"column":0},"end":{"line":94,"column":1}}]},"1":{"type":"branch","line":36,"loc":{"start":{"line":36,"column":23},"end":{"line":36,"column":57}},"locations":[{"start":{"line":36,"column":23},"end":{"line":36,"column":57}}]},"2":{"type":"branch","line":36,"loc":{"start":{"line":36,"column":57},"end":{"line":43,"column":3}},"locations":[{"start":{"line":36,"column":57},"end":{"line":43,"column":3}}]},"3":{"type":"branch","line":48,"loc":{"start":{"line":48,"column":57},"end":{"line":50,"column":3}},"locations":[{"start":{"line":48,"column":57},"end":{"line":50,"column":3}}]},"4":{"type":"branch","line":70,"loc":{"start":{"line":70,"column":2},"end":{"line":72,"column":3}},"locations":[{"start":{"line":70,"column":2},"end":{"line":72,"column":3}}]},"5":{"type":"branch","line":81,"loc":{"start":{"line":81,"column":46},"end":{"line":81,"column":70}},"locations":[{"start":{"line":81,"column":46},"end":{"line":81,"column":70}}]},"6":{"type":"branch","line":87,"loc":{"start":{"line":87,"column":51},"end":{"line":87,"column":75}},"locations":[{"start":{"line":87,"column":51},"end":{"line":87,"column":75}}]},"7":{"type":"branch","line":54,"loc":{"start":{"line":54,"column":41},"end":{"line":58,"column":3}},"locations":[{"start":{"line":54,"column":41},"end":{"line":58,"column":3}}]}},"b":{"0":[4],"1":[0],"2":[0],"3":[2],"4":[0],"5":[0],"6":[0],"7":[8]},"fnMap":{"0":{"name":"harRecorder","decl":{"start":{"line":31,"column":0},"end":{"line":94,"column":1}},"loc":{"start":{"line":31,"column":0},"end":{"line":94,"column":1}},"line":31}},"f":{"0":4}} -,"/root/GitHub/arbiter/src/store/openApiStore.ts": {"path":"/root/GitHub/arbiter/src/store/openApiStore.ts","all":false,"statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":33}},"96":{"start":{"line":97,"column":0},"end":{"line":97,"column":20}},"97":{"start":{"line":98,"column":0},"end":{"line":98,"column":47}},"98":{"start":{"line":99,"column":0},"end":{"line":99,"column":33}},"99":{"start":{"line":100,"column":0},"end":{"line":100,"column":28}},"100":{"start":{"line":101,"column":0},"end":{"line":101,"column":36}},"101":{"start":{"line":102,"column":0},"end":{"line":102,"column":63}},"102":{"start":{"line":103,"column":0},"end":{"line":103,"column":73}},"104":{"start":{"line":105,"column":0},"end":{"line":105,"column":60}},"105":{"start":{"line":106,"column":0},"end":{"line":106,"column":31}},"106":{"start":{"line":107,"column":0},"end":{"line":107,"column":25}},"107":{"start":{"line":108,"column":0},"end":{"line":108,"column":31}},"108":{"start":{"line":109,"column":0},"end":{"line":109,"column":30}},"109":{"start":{"line":110,"column":0},"end":{"line":110,"column":33}},"110":{"start":{"line":111,"column":0},"end":{"line":111,"column":37}},"111":{"start":{"line":112,"column":0},"end":{"line":112,"column":3}},"113":{"start":{"line":114,"column":0},"end":{"line":114,"column":42}},"114":{"start":{"line":115,"column":0},"end":{"line":115,"column":25}},"115":{"start":{"line":116,"column":0},"end":{"line":116,"column":3}},"117":{"start":{"line":118,"column":0},"end":{"line":118,"column":24}},"118":{"start":{"line":119,"column":0},"end":{"line":119,"column":27}},"119":{"start":{"line":120,"column":0},"end":{"line":120,"column":25}},"120":{"start":{"line":121,"column":0},"end":{"line":121,"column":26}},"121":{"start":{"line":122,"column":0},"end":{"line":122,"column":3}},"123":{"start":{"line":124,"column":0},"end":{"line":124,"column":91}},"124":{"start":{"line":125,"column":0},"end":{"line":125,"column":56}},"125":{"start":{"line":126,"column":0},"end":{"line":126,"column":48}},"128":{"start":{"line":129,"column":0},"end":{"line":129,"column":50}},"129":{"start":{"line":130,"column":0},"end":{"line":130,"column":76}},"130":{"start":{"line":131,"column":0},"end":{"line":131,"column":42}},"132":{"start":{"line":133,"column":0},"end":{"line":133,"column":33}},"133":{"start":{"line":134,"column":0},"end":{"line":134,"column":32}},"134":{"start":{"line":135,"column":0},"end":{"line":135,"column":71}},"135":{"start":{"line":136,"column":0},"end":{"line":136,"column":41}},"136":{"start":{"line":137,"column":0},"end":{"line":137,"column":44}},"137":{"start":{"line":138,"column":0},"end":{"line":138,"column":20}},"139":{"start":{"line":140,"column":0},"end":{"line":140,"column":92}},"140":{"start":{"line":141,"column":0},"end":{"line":141,"column":13}},"141":{"start":{"line":142,"column":0},"end":{"line":142,"column":13}},"142":{"start":{"line":143,"column":0},"end":{"line":143,"column":9}},"143":{"start":{"line":144,"column":0},"end":{"line":144,"column":9}},"145":{"start":{"line":146,"column":0},"end":{"line":146,"column":14}},"146":{"start":{"line":147,"column":0},"end":{"line":147,"column":23}},"147":{"start":{"line":148,"column":0},"end":{"line":148,"column":37}},"148":{"start":{"line":149,"column":0},"end":{"line":149,"column":61}},"149":{"start":{"line":150,"column":0},"end":{"line":150,"column":8}},"150":{"start":{"line":151,"column":0},"end":{"line":151,"column":5}},"153":{"start":{"line":154,"column":0},"end":{"line":154,"column":12}},"154":{"start":{"line":155,"column":0},"end":{"line":155,"column":21}},"155":{"start":{"line":156,"column":0},"end":{"line":156,"column":20}},"156":{"start":{"line":157,"column":0},"end":{"line":157,"column":6}},"157":{"start":{"line":158,"column":0},"end":{"line":158,"column":3}},"159":{"start":{"line":160,"column":0},"end":{"line":160,"column":66}},"160":{"start":{"line":161,"column":0},"end":{"line":161,"column":46}},"161":{"start":{"line":162,"column":0},"end":{"line":162,"column":29}},"162":{"start":{"line":163,"column":0},"end":{"line":163,"column":80}},"165":{"start":{"line":166,"column":0},"end":{"line":166,"column":73}},"168":{"start":{"line":169,"column":0},"end":{"line":169,"column":89}},"169":{"start":{"line":170,"column":0},"end":{"line":170,"column":16}},"170":{"start":{"line":171,"column":0},"end":{"line":171,"column":24}},"171":{"start":{"line":172,"column":0},"end":{"line":172,"column":32}},"172":{"start":{"line":173,"column":0},"end":{"line":173,"column":22}},"173":{"start":{"line":174,"column":0},"end":{"line":174,"column":10}},"174":{"start":{"line":175,"column":0},"end":{"line":175,"column":7}},"177":{"start":{"line":178,"column":0},"end":{"line":178,"column":14}},"178":{"start":{"line":179,"column":0},"end":{"line":179,"column":22}},"179":{"start":{"line":180,"column":0},"end":{"line":180,"column":16}},"180":{"start":{"line":181,"column":0},"end":{"line":181,"column":25}},"181":{"start":{"line":182,"column":0},"end":{"line":182,"column":28}},"182":{"start":{"line":183,"column":0},"end":{"line":183,"column":10}},"183":{"start":{"line":184,"column":0},"end":{"line":184,"column":20}},"184":{"start":{"line":185,"column":0},"end":{"line":185,"column":8}},"185":{"start":{"line":186,"column":0},"end":{"line":186,"column":5}},"187":{"start":{"line":188,"column":0},"end":{"line":188,"column":34}},"188":{"start":{"line":189,"column":0},"end":{"line":189,"column":70}},"189":{"start":{"line":190,"column":0},"end":{"line":190,"column":55}},"190":{"start":{"line":191,"column":0},"end":{"line":191,"column":57}},"191":{"start":{"line":192,"column":0},"end":{"line":192,"column":7}},"192":{"start":{"line":193,"column":0},"end":{"line":193,"column":14}},"193":{"start":{"line":194,"column":0},"end":{"line":194,"column":23}},"194":{"start":{"line":195,"column":0},"end":{"line":195,"column":19}},"195":{"start":{"line":196,"column":0},"end":{"line":196,"column":20}},"196":{"start":{"line":197,"column":0},"end":{"line":197,"column":8}},"197":{"start":{"line":198,"column":0},"end":{"line":198,"column":5}},"200":{"start":{"line":201,"column":0},"end":{"line":201,"column":75}},"201":{"start":{"line":202,"column":0},"end":{"line":202,"column":25}},"202":{"start":{"line":203,"column":0},"end":{"line":203,"column":25}},"203":{"start":{"line":204,"column":0},"end":{"line":204,"column":27}},"204":{"start":{"line":205,"column":0},"end":{"line":205,"column":26}},"205":{"start":{"line":206,"column":0},"end":{"line":206,"column":25}},"206":{"start":{"line":207,"column":0},"end":{"line":207,"column":28}},"207":{"start":{"line":208,"column":0},"end":{"line":208,"column":26}},"208":{"start":{"line":209,"column":0},"end":{"line":209,"column":6}},"210":{"start":{"line":211,"column":0},"end":{"line":211,"column":13}},"211":{"start":{"line":212,"column":0},"end":{"line":212,"column":44}},"212":{"start":{"line":213,"column":0},"end":{"line":213,"column":18}},"213":{"start":{"line":214,"column":0},"end":{"line":214,"column":6}},"214":{"start":{"line":215,"column":0},"end":{"line":215,"column":3}},"216":{"start":{"line":217,"column":0},"end":{"line":217,"column":25}},"217":{"start":{"line":218,"column":0},"end":{"line":218,"column":17}},"218":{"start":{"line":219,"column":0},"end":{"line":219,"column":19}},"219":{"start":{"line":220,"column":0},"end":{"line":220,"column":25}},"220":{"start":{"line":221,"column":0},"end":{"line":221,"column":26}},"221":{"start":{"line":222,"column":0},"end":{"line":222,"column":11}},"222":{"start":{"line":223,"column":0},"end":{"line":223,"column":27}},"223":{"start":{"line":224,"column":0},"end":{"line":224,"column":29}},"224":{"start":{"line":225,"column":0},"end":{"line":225,"column":41}},"225":{"start":{"line":226,"column":0},"end":{"line":226,"column":14}},"226":{"start":{"line":227,"column":0},"end":{"line":227,"column":16}},"227":{"start":{"line":228,"column":0},"end":{"line":228,"column":37}},"228":{"start":{"line":229,"column":0},"end":{"line":229,"column":83}},"229":{"start":{"line":230,"column":0},"end":{"line":230,"column":32}},"230":{"start":{"line":231,"column":0},"end":{"line":231,"column":54}},"231":{"start":{"line":232,"column":0},"end":{"line":232,"column":37}},"232":{"start":{"line":233,"column":0},"end":{"line":233,"column":63}},"233":{"start":{"line":234,"column":0},"end":{"line":234,"column":60}},"234":{"start":{"line":235,"column":0},"end":{"line":235,"column":14}},"235":{"start":{"line":236,"column":0},"end":{"line":236,"column":56}},"236":{"start":{"line":237,"column":0},"end":{"line":237,"column":37}},"237":{"start":{"line":238,"column":0},"end":{"line":238,"column":18}},"238":{"start":{"line":239,"column":0},"end":{"line":239,"column":60}},"239":{"start":{"line":240,"column":0},"end":{"line":240,"column":14}},"240":{"start":{"line":241,"column":0},"end":{"line":241,"column":34}},"241":{"start":{"line":242,"column":0},"end":{"line":242,"column":40}},"242":{"start":{"line":243,"column":0},"end":{"line":243,"column":44}},"243":{"start":{"line":244,"column":0},"end":{"line":244,"column":21}},"244":{"start":{"line":245,"column":0},"end":{"line":245,"column":8}},"245":{"start":{"line":246,"column":0},"end":{"line":246,"column":17}},"246":{"start":{"line":247,"column":0},"end":{"line":247,"column":32}},"247":{"start":{"line":248,"column":0},"end":{"line":248,"column":61}},"248":{"start":{"line":249,"column":0},"end":{"line":249,"column":32}},"249":{"start":{"line":250,"column":0},"end":{"line":250,"column":55}},"250":{"start":{"line":251,"column":0},"end":{"line":251,"column":37}},"251":{"start":{"line":252,"column":0},"end":{"line":252,"column":63}},"252":{"start":{"line":253,"column":0},"end":{"line":253,"column":60}},"253":{"start":{"line":254,"column":0},"end":{"line":254,"column":14}},"254":{"start":{"line":255,"column":0},"end":{"line":255,"column":18}},"255":{"start":{"line":256,"column":0},"end":{"line":256,"column":73}},"256":{"start":{"line":257,"column":0},"end":{"line":257,"column":63}},"257":{"start":{"line":258,"column":0},"end":{"line":258,"column":66}},"258":{"start":{"line":259,"column":0},"end":{"line":259,"column":9}},"259":{"start":{"line":260,"column":0},"end":{"line":260,"column":7}},"260":{"start":{"line":261,"column":0},"end":{"line":261,"column":6}},"262":{"start":{"line":263,"column":0},"end":{"line":263,"column":32}},"263":{"start":{"line":264,"column":0},"end":{"line":264,"column":3}},"265":{"start":{"line":266,"column":0},"end":{"line":266,"column":67}},"266":{"start":{"line":267,"column":0},"end":{"line":267,"column":52}},"267":{"start":{"line":268,"column":0},"end":{"line":268,"column":16}},"268":{"start":{"line":269,"column":0},"end":{"line":269,"column":5}},"269":{"start":{"line":270,"column":0},"end":{"line":270,"column":41}},"270":{"start":{"line":271,"column":0},"end":{"line":271,"column":53}},"271":{"start":{"line":272,"column":0},"end":{"line":272,"column":32}},"272":{"start":{"line":273,"column":0},"end":{"line":273,"column":7}},"273":{"start":{"line":274,"column":0},"end":{"line":274,"column":35}},"274":{"start":{"line":275,"column":0},"end":{"line":275,"column":3}},"276":{"start":{"line":277,"column":0},"end":{"line":277,"column":61}},"278":{"start":{"line":279,"column":0},"end":{"line":279,"column":43}},"279":{"start":{"line":280,"column":0},"end":{"line":280,"column":49}},"281":{"start":{"line":282,"column":0},"end":{"line":282,"column":28}},"282":{"start":{"line":283,"column":0},"end":{"line":283,"column":20}},"283":{"start":{"line":284,"column":0},"end":{"line":284,"column":18}},"284":{"start":{"line":285,"column":0},"end":{"line":285,"column":25}},"285":{"start":{"line":286,"column":0},"end":{"line":286,"column":45}},"286":{"start":{"line":287,"column":0},"end":{"line":287,"column":37}},"287":{"start":{"line":288,"column":0},"end":{"line":288,"column":10}},"288":{"start":{"line":289,"column":0},"end":{"line":289,"column":14}},"290":{"start":{"line":291,"column":0},"end":{"line":291,"column":20}},"291":{"start":{"line":292,"column":0},"end":{"line":292,"column":18}},"292":{"start":{"line":293,"column":0},"end":{"line":293,"column":25}},"293":{"start":{"line":294,"column":0},"end":{"line":294,"column":36}},"294":{"start":{"line":295,"column":0},"end":{"line":295,"column":23}},"295":{"start":{"line":296,"column":0},"end":{"line":296,"column":70}},"296":{"start":{"line":297,"column":0},"end":{"line":297,"column":23}},"297":{"start":{"line":298,"column":0},"end":{"line":298,"column":38}},"298":{"start":{"line":299,"column":0},"end":{"line":299,"column":39}},"299":{"start":{"line":300,"column":0},"end":{"line":300,"column":15}},"300":{"start":{"line":301,"column":0},"end":{"line":301,"column":13}},"301":{"start":{"line":302,"column":0},"end":{"line":302,"column":11}},"302":{"start":{"line":303,"column":0},"end":{"line":303,"column":10}},"303":{"start":{"line":304,"column":0},"end":{"line":304,"column":14}},"305":{"start":{"line":306,"column":0},"end":{"line":306,"column":18}},"306":{"start":{"line":307,"column":0},"end":{"line":307,"column":18}},"307":{"start":{"line":308,"column":0},"end":{"line":308,"column":23}},"308":{"start":{"line":309,"column":0},"end":{"line":309,"column":45}},"309":{"start":{"line":310,"column":0},"end":{"line":310,"column":10}},"310":{"start":{"line":311,"column":0},"end":{"line":311,"column":14}},"312":{"start":{"line":313,"column":0},"end":{"line":313,"column":27}},"313":{"start":{"line":314,"column":0},"end":{"line":314,"column":18}},"314":{"start":{"line":315,"column":0},"end":{"line":315,"column":32}},"315":{"start":{"line":316,"column":0},"end":{"line":316,"column":111}},"316":{"start":{"line":317,"column":0},"end":{"line":317,"column":10}},"317":{"start":{"line":318,"column":0},"end":{"line":318,"column":14}},"319":{"start":{"line":320,"column":0},"end":{"line":320,"column":14}},"320":{"start":{"line":321,"column":0},"end":{"line":321,"column":71}},"321":{"start":{"line":322,"column":0},"end":{"line":322,"column":5}},"323":{"start":{"line":324,"column":0},"end":{"line":324,"column":49}},"324":{"start":{"line":325,"column":0},"end":{"line":325,"column":22}},"325":{"start":{"line":326,"column":0},"end":{"line":326,"column":3}},"327":{"start":{"line":328,"column":0},"end":{"line":328,"column":24}},"328":{"start":{"line":329,"column":0},"end":{"line":329,"column":17}},"329":{"start":{"line":330,"column":0},"end":{"line":330,"column":19}},"330":{"start":{"line":331,"column":0},"end":{"line":331,"column":25}},"331":{"start":{"line":332,"column":0},"end":{"line":332,"column":26}},"332":{"start":{"line":333,"column":0},"end":{"line":333,"column":11}},"333":{"start":{"line":334,"column":0},"end":{"line":334,"column":36}},"334":{"start":{"line":335,"column":0},"end":{"line":335,"column":63}},"335":{"start":{"line":336,"column":0},"end":{"line":336,"column":11}},"336":{"start":{"line":337,"column":0},"end":{"line":337,"column":13}},"337":{"start":{"line":338,"column":0},"end":{"line":338,"column":20}},"338":{"start":{"line":339,"column":0},"end":{"line":339,"column":21}},"339":{"start":{"line":340,"column":0},"end":{"line":340,"column":65}},"340":{"start":{"line":341,"column":0},"end":{"line":341,"column":24}},"341":{"start":{"line":342,"column":0},"end":{"line":342,"column":19}},"342":{"start":{"line":343,"column":0},"end":{"line":343,"column":7}},"343":{"start":{"line":344,"column":0},"end":{"line":344,"column":6}},"346":{"start":{"line":347,"column":0},"end":{"line":347,"column":27}},"347":{"start":{"line":348,"column":0},"end":{"line":348,"column":60}},"348":{"start":{"line":349,"column":0},"end":{"line":349,"column":60}},"349":{"start":{"line":350,"column":0},"end":{"line":350,"column":63}},"350":{"start":{"line":351,"column":0},"end":{"line":351,"column":9}},"351":{"start":{"line":352,"column":0},"end":{"line":352,"column":5}},"354":{"start":{"line":355,"column":0},"end":{"line":355,"column":56}},"357":{"start":{"line":358,"column":0},"end":{"line":358,"column":51}},"358":{"start":{"line":359,"column":0},"end":{"line":359,"column":33}},"359":{"start":{"line":360,"column":0},"end":{"line":360,"column":39}},"360":{"start":{"line":361,"column":0},"end":{"line":361,"column":65}},"361":{"start":{"line":362,"column":0},"end":{"line":362,"column":34}},"362":{"start":{"line":363,"column":0},"end":{"line":363,"column":26}},"363":{"start":{"line":364,"column":0},"end":{"line":364,"column":21}},"364":{"start":{"line":365,"column":0},"end":{"line":365,"column":25}},"365":{"start":{"line":366,"column":0},"end":{"line":366,"column":19}},"366":{"start":{"line":367,"column":0},"end":{"line":367,"column":27}},"367":{"start":{"line":368,"column":0},"end":{"line":368,"column":70}},"368":{"start":{"line":369,"column":0},"end":{"line":369,"column":11}},"369":{"start":{"line":370,"column":0},"end":{"line":370,"column":11}},"370":{"start":{"line":371,"column":0},"end":{"line":371,"column":7}},"371":{"start":{"line":372,"column":0},"end":{"line":372,"column":7}},"374":{"start":{"line":375,"column":0},"end":{"line":375,"column":61}},"375":{"start":{"line":376,"column":0},"end":{"line":376,"column":59}},"376":{"start":{"line":377,"column":0},"end":{"line":377,"column":34}},"377":{"start":{"line":378,"column":0},"end":{"line":378,"column":20}},"378":{"start":{"line":379,"column":0},"end":{"line":379,"column":22}},"379":{"start":{"line":380,"column":0},"end":{"line":380,"column":26}},"380":{"start":{"line":381,"column":0},"end":{"line":381,"column":19}},"381":{"start":{"line":382,"column":0},"end":{"line":382,"column":27}},"382":{"start":{"line":383,"column":0},"end":{"line":383,"column":26}},"383":{"start":{"line":384,"column":0},"end":{"line":384,"column":11}},"384":{"start":{"line":385,"column":0},"end":{"line":385,"column":11}},"385":{"start":{"line":386,"column":0},"end":{"line":386,"column":7}},"386":{"start":{"line":387,"column":0},"end":{"line":387,"column":7}},"389":{"start":{"line":390,"column":0},"end":{"line":390,"column":26}},"390":{"start":{"line":391,"column":0},"end":{"line":391,"column":66}},"391":{"start":{"line":392,"column":0},"end":{"line":392,"column":62}},"392":{"start":{"line":393,"column":0},"end":{"line":393,"column":36}},"393":{"start":{"line":394,"column":0},"end":{"line":394,"column":23}},"394":{"start":{"line":395,"column":0},"end":{"line":395,"column":25}},"395":{"start":{"line":396,"column":0},"end":{"line":396,"column":28}},"396":{"start":{"line":397,"column":0},"end":{"line":397,"column":21}},"397":{"start":{"line":398,"column":0},"end":{"line":398,"column":29}},"398":{"start":{"line":399,"column":0},"end":{"line":399,"column":28}},"399":{"start":{"line":400,"column":0},"end":{"line":400,"column":13}},"400":{"start":{"line":401,"column":0},"end":{"line":401,"column":13}},"401":{"start":{"line":402,"column":0},"end":{"line":402,"column":9}},"402":{"start":{"line":403,"column":0},"end":{"line":403,"column":9}},"403":{"start":{"line":404,"column":0},"end":{"line":404,"column":5}},"406":{"start":{"line":407,"column":0},"end":{"line":407,"column":57}},"407":{"start":{"line":408,"column":0},"end":{"line":408,"column":68}},"408":{"start":{"line":409,"column":0},"end":{"line":409,"column":79}},"409":{"start":{"line":410,"column":0},"end":{"line":410,"column":61}},"410":{"start":{"line":411,"column":0},"end":{"line":411,"column":53}},"411":{"start":{"line":412,"column":0},"end":{"line":412,"column":16}},"412":{"start":{"line":413,"column":0},"end":{"line":413,"column":10}},"413":{"start":{"line":414,"column":0},"end":{"line":414,"column":7}},"414":{"start":{"line":415,"column":0},"end":{"line":415,"column":5}},"417":{"start":{"line":418,"column":0},"end":{"line":418,"column":75}},"420":{"start":{"line":421,"column":0},"end":{"line":421,"column":47}},"421":{"start":{"line":422,"column":0},"end":{"line":422,"column":45}},"422":{"start":{"line":423,"column":0},"end":{"line":423,"column":68}},"423":{"start":{"line":424,"column":0},"end":{"line":424,"column":19}},"424":{"start":{"line":425,"column":0},"end":{"line":425,"column":8}},"425":{"start":{"line":426,"column":0},"end":{"line":426,"column":5}},"428":{"start":{"line":429,"column":0},"end":{"line":429,"column":60}},"429":{"start":{"line":430,"column":0},"end":{"line":430,"column":31}},"430":{"start":{"line":431,"column":0},"end":{"line":431,"column":31}},"431":{"start":{"line":432,"column":0},"end":{"line":432,"column":5}},"434":{"start":{"line":435,"column":0},"end":{"line":435,"column":65}},"437":{"start":{"line":438,"column":0},"end":{"line":438,"column":73}},"438":{"start":{"line":439,"column":0},"end":{"line":439,"column":66}},"441":{"start":{"line":442,"column":0},"end":{"line":442,"column":40}},"442":{"start":{"line":443,"column":0},"end":{"line":443,"column":53}},"445":{"start":{"line":446,"column":0},"end":{"line":446,"column":64}},"448":{"start":{"line":449,"column":0},"end":{"line":449,"column":48}},"449":{"start":{"line":450,"column":0},"end":{"line":450,"column":26}},"450":{"start":{"line":451,"column":0},"end":{"line":451,"column":6}},"453":{"start":{"line":454,"column":0},"end":{"line":454,"column":71}},"454":{"start":{"line":455,"column":0},"end":{"line":455,"column":117}},"455":{"start":{"line":456,"column":0},"end":{"line":456,"column":21}},"456":{"start":{"line":457,"column":0},"end":{"line":457,"column":19}},"457":{"start":{"line":458,"column":0},"end":{"line":458,"column":27}},"458":{"start":{"line":459,"column":0},"end":{"line":459,"column":26}},"459":{"start":{"line":460,"column":0},"end":{"line":460,"column":12}},"460":{"start":{"line":461,"column":0},"end":{"line":461,"column":48}},"461":{"start":{"line":462,"column":0},"end":{"line":462,"column":10}},"462":{"start":{"line":463,"column":0},"end":{"line":463,"column":19}},"463":{"start":{"line":464,"column":0},"end":{"line":464,"column":67}},"464":{"start":{"line":465,"column":0},"end":{"line":465,"column":5}},"466":{"start":{"line":467,"column":0},"end":{"line":467,"column":38}},"469":{"start":{"line":470,"column":0},"end":{"line":470,"column":57}},"470":{"start":{"line":471,"column":0},"end":{"line":471,"column":3}},"472":{"start":{"line":473,"column":0},"end":{"line":473,"column":49}},"473":{"start":{"line":474,"column":0},"end":{"line":474,"column":108}},"474":{"start":{"line":475,"column":0},"end":{"line":475,"column":44}},"476":{"start":{"line":477,"column":0},"end":{"line":477,"column":23}},"477":{"start":{"line":478,"column":0},"end":{"line":478,"column":51}},"478":{"start":{"line":479,"column":0},"end":{"line":479,"column":7}},"480":{"start":{"line":481,"column":0},"end":{"line":481,"column":54}},"481":{"start":{"line":482,"column":0},"end":{"line":482,"column":51}},"482":{"start":{"line":483,"column":0},"end":{"line":483,"column":34}},"483":{"start":{"line":484,"column":0},"end":{"line":484,"column":8}},"486":{"start":{"line":487,"column":0},"end":{"line":487,"column":39}},"487":{"start":{"line":488,"column":0},"end":{"line":488,"column":47}},"488":{"start":{"line":489,"column":0},"end":{"line":489,"column":7}},"491":{"start":{"line":492,"column":0},"end":{"line":492,"column":29}},"492":{"start":{"line":493,"column":0},"end":{"line":493,"column":49}},"493":{"start":{"line":494,"column":0},"end":{"line":494,"column":7}},"496":{"start":{"line":497,"column":0},"end":{"line":497,"column":26}},"497":{"start":{"line":498,"column":0},"end":{"line":498,"column":43}},"498":{"start":{"line":499,"column":0},"end":{"line":499,"column":7}},"500":{"start":{"line":501,"column":0},"end":{"line":501,"column":36}},"501":{"start":{"line":502,"column":0},"end":{"line":502,"column":17}},"502":{"start":{"line":503,"column":0},"end":{"line":503,"column":11}},"504":{"start":{"line":505,"column":0},"end":{"line":505,"column":40}},"505":{"start":{"line":506,"column":0},"end":{"line":506,"column":23}},"506":{"start":{"line":507,"column":0},"end":{"line":507,"column":13}},"507":{"start":{"line":508,"column":0},"end":{"line":508,"column":45}},"508":{"start":{"line":509,"column":0},"end":{"line":509,"column":25}},"509":{"start":{"line":510,"column":0},"end":{"line":510,"column":84}},"510":{"start":{"line":511,"column":0},"end":{"line":511,"column":8}},"511":{"start":{"line":512,"column":0},"end":{"line":512,"column":17}},"512":{"start":{"line":513,"column":0},"end":{"line":513,"column":28}},"513":{"start":{"line":514,"column":0},"end":{"line":514,"column":9}},"514":{"start":{"line":515,"column":0},"end":{"line":515,"column":12}},"515":{"start":{"line":516,"column":0},"end":{"line":516,"column":19}},"516":{"start":{"line":517,"column":0},"end":{"line":517,"column":65}},"517":{"start":{"line":518,"column":0},"end":{"line":518,"column":7}},"518":{"start":{"line":519,"column":0},"end":{"line":519,"column":6}},"520":{"start":{"line":521,"column":0},"end":{"line":521,"column":16}},"521":{"start":{"line":522,"column":0},"end":{"line":522,"column":3}},"523":{"start":{"line":524,"column":0},"end":{"line":524,"column":41}},"524":{"start":{"line":525,"column":0},"end":{"line":525,"column":39}},"525":{"start":{"line":526,"column":0},"end":{"line":526,"column":28}},"526":{"start":{"line":527,"column":0},"end":{"line":527,"column":16}},"527":{"start":{"line":528,"column":0},"end":{"line":528,"column":23}},"528":{"start":{"line":529,"column":0},"end":{"line":529,"column":18}},"529":{"start":{"line":530,"column":0},"end":{"line":530,"column":7}},"530":{"start":{"line":531,"column":0},"end":{"line":531,"column":3}},"532":{"start":{"line":533,"column":0},"end":{"line":533,"column":51}},"533":{"start":{"line":534,"column":0},"end":{"line":534,"column":39}},"534":{"start":{"line":535,"column":0},"end":{"line":535,"column":49}},"537":{"start":{"line":538,"column":0},"end":{"line":538,"column":36}},"538":{"start":{"line":539,"column":0},"end":{"line":539,"column":51}},"539":{"start":{"line":540,"column":0},"end":{"line":540,"column":5}},"542":{"start":{"line":543,"column":0},"end":{"line":543,"column":21}},"543":{"start":{"line":544,"column":0},"end":{"line":544,"column":43}},"544":{"start":{"line":545,"column":0},"end":{"line":545,"column":35}},"545":{"start":{"line":546,"column":0},"end":{"line":546,"column":6}},"548":{"start":{"line":549,"column":0},"end":{"line":549,"column":21}},"549":{"start":{"line":550,"column":0},"end":{"line":550,"column":43}},"550":{"start":{"line":551,"column":0},"end":{"line":551,"column":14}},"551":{"start":{"line":552,"column":0},"end":{"line":552,"column":6}},"552":{"start":{"line":553,"column":0},"end":{"line":553,"column":3}},"554":{"start":{"line":555,"column":0},"end":{"line":555,"column":29}},"555":{"start":{"line":556,"column":0},"end":{"line":556,"column":12}},"556":{"start":{"line":557,"column":0},"end":{"line":557,"column":12}},"557":{"start":{"line":558,"column":0},"end":{"line":558,"column":23}},"558":{"start":{"line":559,"column":0},"end":{"line":559,"column":18}},"559":{"start":{"line":560,"column":0},"end":{"line":560,"column":26}},"560":{"start":{"line":561,"column":0},"end":{"line":561,"column":27}},"561":{"start":{"line":562,"column":0},"end":{"line":562,"column":10}},"562":{"start":{"line":563,"column":0},"end":{"line":563,"column":33}},"563":{"start":{"line":564,"column":0},"end":{"line":564,"column":8}},"564":{"start":{"line":565,"column":0},"end":{"line":565,"column":6}},"565":{"start":{"line":566,"column":0},"end":{"line":566,"column":3}},"566":{"start":{"line":567,"column":0},"end":{"line":567,"column":1}},"568":{"start":{"line":569,"column":0},"end":{"line":569,"column":47}}},"s":{"0":1,"1":1,"2":1,"96":1,"97":2,"98":2,"99":2,"100":2,"101":2,"102":2,"104":2,"105":2,"106":2,"107":2,"108":2,"109":2,"110":2,"111":2,"113":2,"114":0,"115":0,"117":2,"118":14,"119":14,"120":14,"121":14,"123":2,"124":27,"125":27,"128":27,"129":6,"130":6,"132":6,"133":18,"134":18,"135":18,"136":6,"137":18,"139":12,"140":12,"141":18,"142":18,"143":6,"145":6,"146":6,"147":6,"148":6,"149":6,"150":6,"153":12,"154":12,"155":12,"156":12,"157":27,"159":2,"160":30,"161":30,"162":0,"165":0,"168":0,"169":0,"170":0,"171":0,"172":0,"173":0,"174":0,"177":0,"178":0,"179":0,"180":0,"181":0,"182":0,"183":0,"184":0,"185":0,"187":30,"188":15,"189":15,"190":15,"191":15,"192":15,"193":15,"194":15,"195":15,"196":15,"197":15,"200":15,"201":15,"202":15,"203":15,"204":15,"205":15,"206":15,"207":15,"208":15,"210":15,"211":30,"212":30,"213":30,"214":30,"216":2,"217":15,"218":15,"219":15,"220":15,"221":15,"222":15,"223":15,"224":15,"225":15,"226":15,"227":15,"228":15,"229":15,"230":15,"231":15,"232":14,"233":14,"234":15,"235":15,"236":15,"237":2,"238":2,"239":15,"240":15,"241":0,"242":0,"243":15,"244":15,"245":15,"246":15,"247":15,"248":15,"249":15,"250":15,"251":5,"252":5,"253":15,"254":15,"255":15,"256":15,"257":15,"258":15,"259":15,"260":15,"262":15,"263":15,"265":2,"266":15,"267":14,"268":14,"269":1,"270":1,"271":2,"272":1,"273":1,"274":15,"276":2,"278":6,"279":6,"281":6,"282":6,"283":2,"284":2,"285":2,"286":2,"287":2,"288":2,"290":6,"291":1,"292":1,"293":1,"294":0,"295":0,"296":0,"297":0,"298":0,"299":0,"300":0,"301":0,"302":1,"303":1,"305":6,"306":2,"307":2,"308":2,"309":2,"310":2,"312":6,"313":1,"314":1,"315":1,"316":1,"317":1,"319":6,"320":0,"321":6,"323":6,"324":6,"325":6,"327":2,"328":15,"329":15,"330":15,"331":15,"332":15,"333":15,"334":15,"335":15,"336":15,"337":15,"338":15,"339":15,"340":1,"341":1,"342":1,"343":15,"346":15,"347":5,"348":6,"349":6,"350":5,"351":5,"354":15,"357":15,"358":15,"359":0,"360":0,"361":0,"362":0,"363":0,"364":0,"365":0,"366":0,"367":0,"368":0,"369":0,"370":0,"371":15,"374":15,"375":2,"376":2,"377":2,"378":2,"379":2,"380":2,"381":2,"382":2,"383":2,"384":2,"385":2,"386":15,"389":15,"390":9,"391":14,"392":14,"393":14,"394":14,"395":14,"396":14,"397":14,"398":14,"399":14,"400":14,"401":14,"402":9,"403":9,"406":15,"407":0,"408":0,"409":0,"410":0,"411":0,"412":0,"413":0,"414":0,"417":15,"420":15,"421":15,"422":15,"423":15,"424":15,"425":15,"428":15,"429":15,"430":0,"431":0,"434":15,"437":15,"438":15,"441":15,"442":15,"445":15,"448":15,"449":15,"450":15,"453":15,"454":5,"455":5,"456":5,"457":5,"458":5,"459":5,"460":5,"461":5,"462":5,"463":5,"464":5,"466":15,"469":15,"470":15,"472":2,"473":10,"474":11,"476":11,"477":11,"478":11,"480":11,"481":11,"482":11,"483":11,"486":11,"487":5,"488":5,"491":11,"492":1,"493":1,"496":11,"497":5,"498":5,"500":11,"501":11,"502":10,"504":10,"505":10,"506":10,"507":10,"508":10,"509":10,"510":10,"511":10,"512":10,"513":10,"514":10,"515":10,"516":10,"517":10,"518":10,"520":10,"521":10,"523":2,"524":2,"525":2,"526":2,"527":2,"528":2,"529":2,"530":2,"532":2,"533":1,"534":1,"537":1,"538":1,"539":1,"542":1,"543":1,"544":1,"545":1,"548":1,"549":1,"550":1,"551":1,"552":1,"554":2,"555":10,"556":10,"557":10,"558":10,"559":10,"560":10,"561":10,"562":10,"563":10,"564":10,"565":10,"566":2,"568":1},"branchMap":{"0":{"type":"branch","line":97,"loc":{"start":{"line":97,"column":19},"end":{"line":567,"column":1}},"locations":[{"start":{"line":97,"column":19},"end":{"line":567,"column":1}}]},"1":{"type":"branch","line":105,"loc":{"start":{"line":105,"column":2},"end":{"line":112,"column":3}},"locations":[{"start":{"line":105,"column":2},"end":{"line":112,"column":3}}]},"2":{"type":"branch","line":118,"loc":{"start":{"line":118,"column":9},"end":{"line":122,"column":3}},"locations":[{"start":{"line":118,"column":9},"end":{"line":122,"column":3}}]},"3":{"type":"branch","line":124,"loc":{"start":{"line":124,"column":10},"end":{"line":158,"column":3}},"locations":[{"start":{"line":124,"column":10},"end":{"line":158,"column":3}}]},"4":{"type":"branch","line":125,"loc":{"start":{"line":125,"column":30},"end":{"line":125,"column":56}},"locations":[{"start":{"line":125,"column":30},"end":{"line":125,"column":56}}]},"5":{"type":"branch","line":126,"loc":{"start":{"line":126,"column":30},"end":{"line":126,"column":48}},"locations":[{"start":{"line":126,"column":30},"end":{"line":126,"column":48}}]},"6":{"type":"branch","line":126,"loc":{"start":{"line":126,"column":46},"end":{"line":129,"column":49}},"locations":[{"start":{"line":126,"column":46},"end":{"line":129,"column":49}}]},"7":{"type":"branch","line":129,"loc":{"start":{"line":129,"column":49},"end":{"line":151,"column":5}},"locations":[{"start":{"line":129,"column":49},"end":{"line":151,"column":5}}]},"8":{"type":"branch","line":151,"loc":{"start":{"line":151,"column":4},"end":{"line":157,"column":6}},"locations":[{"start":{"line":151,"column":4},"end":{"line":157,"column":6}}]},"9":{"type":"branch","line":129,"loc":{"start":{"line":129,"column":22},"end":{"line":129,"column":46}},"locations":[{"start":{"line":129,"column":22},"end":{"line":129,"column":46}}]},"10":{"type":"branch","line":133,"loc":{"start":{"line":133,"column":22},"end":{"line":144,"column":7}},"locations":[{"start":{"line":133,"column":22},"end":{"line":144,"column":7}}]},"11":{"type":"branch","line":135,"loc":{"start":{"line":135,"column":52},"end":{"line":142,"column":11}},"locations":[{"start":{"line":135,"column":52},"end":{"line":142,"column":11}}]},"12":{"type":"branch","line":136,"loc":{"start":{"line":136,"column":40},"end":{"line":138,"column":19}},"locations":[{"start":{"line":136,"column":40},"end":{"line":138,"column":19}}]},"13":{"type":"branch","line":138,"loc":{"start":{"line":138,"column":12},"end":{"line":141,"column":13}},"locations":[{"start":{"line":138,"column":12},"end":{"line":141,"column":13}}]},"14":{"type":"branch","line":160,"loc":{"start":{"line":160,"column":10},"end":{"line":215,"column":3}},"locations":[{"start":{"line":160,"column":10},"end":{"line":215,"column":3}}]},"15":{"type":"branch","line":161,"loc":{"start":{"line":161,"column":22},"end":{"line":161,"column":46}},"locations":[{"start":{"line":161,"column":22},"end":{"line":161,"column":46}}]},"16":{"type":"branch","line":162,"loc":{"start":{"line":162,"column":28},"end":{"line":186,"column":5}},"locations":[{"start":{"line":162,"column":28},"end":{"line":186,"column":5}}]},"17":{"type":"branch","line":188,"loc":{"start":{"line":188,"column":33},"end":{"line":212,"column":35}},"locations":[{"start":{"line":188,"column":33},"end":{"line":212,"column":35}}]},"18":{"type":"branch","line":212,"loc":{"start":{"line":212,"column":30},"end":{"line":212,"column":44}},"locations":[{"start":{"line":212,"column":30},"end":{"line":212,"column":44}}]},"19":{"type":"branch","line":217,"loc":{"start":{"line":217,"column":10},"end":{"line":264,"column":3}},"locations":[{"start":{"line":217,"column":10},"end":{"line":264,"column":3}}]},"20":{"type":"branch","line":231,"loc":{"start":{"line":231,"column":40},"end":{"line":231,"column":53}},"locations":[{"start":{"line":231,"column":40},"end":{"line":231,"column":53}}]},"21":{"type":"branch","line":236,"loc":{"start":{"line":236,"column":44},"end":{"line":236,"column":55}},"locations":[{"start":{"line":236,"column":44},"end":{"line":236,"column":55}}]},"22":{"type":"branch","line":241,"loc":{"start":{"line":241,"column":26},"end":{"line":244,"column":12}},"locations":[{"start":{"line":241,"column":26},"end":{"line":244,"column":12}}]},"23":{"type":"branch","line":248,"loc":{"start":{"line":248,"column":40},"end":{"line":248,"column":53}},"locations":[{"start":{"line":248,"column":40},"end":{"line":248,"column":53}}]},"24":{"type":"branch","line":248,"loc":{"start":{"line":248,"column":46},"end":{"line":248,"column":61}},"locations":[{"start":{"line":248,"column":46},"end":{"line":248,"column":61}}]},"25":{"type":"branch","line":250,"loc":{"start":{"line":250,"column":41},"end":{"line":250,"column":54}},"locations":[{"start":{"line":250,"column":41},"end":{"line":250,"column":54}}]},"26":{"type":"branch","line":256,"loc":{"start":{"line":256,"column":62},"end":{"line":256,"column":73}},"locations":[{"start":{"line":256,"column":62},"end":{"line":256,"column":73}}]},"27":{"type":"branch","line":257,"loc":{"start":{"line":257,"column":29},"end":{"line":257,"column":63}},"locations":[{"start":{"line":257,"column":29},"end":{"line":257,"column":63}}]},"28":{"type":"branch","line":258,"loc":{"start":{"line":258,"column":60},"end":{"line":258,"column":66}},"locations":[{"start":{"line":258,"column":60},"end":{"line":258,"column":66}}]},"29":{"type":"branch","line":232,"loc":{"start":{"line":232,"column":15},"end":{"line":235,"column":12}},"locations":[{"start":{"line":232,"column":15},"end":{"line":235,"column":12}}]},"30":{"type":"branch","line":237,"loc":{"start":{"line":237,"column":15},"end":{"line":240,"column":12}},"locations":[{"start":{"line":237,"column":15},"end":{"line":240,"column":12}}]},"31":{"type":"branch","line":251,"loc":{"start":{"line":251,"column":15},"end":{"line":254,"column":12}},"locations":[{"start":{"line":251,"column":15},"end":{"line":254,"column":12}}]},"32":{"type":"branch","line":266,"loc":{"start":{"line":266,"column":10},"end":{"line":275,"column":3}},"locations":[{"start":{"line":266,"column":10},"end":{"line":275,"column":3}}]},"33":{"type":"branch","line":267,"loc":{"start":{"line":267,"column":51},"end":{"line":269,"column":5}},"locations":[{"start":{"line":267,"column":51},"end":{"line":269,"column":5}}]},"34":{"type":"branch","line":269,"loc":{"start":{"line":269,"column":4},"end":{"line":274,"column":35}},"locations":[{"start":{"line":269,"column":4},"end":{"line":274,"column":35}}]},"35":{"type":"branch","line":271,"loc":{"start":{"line":271,"column":34},"end":{"line":273,"column":5}},"locations":[{"start":{"line":271,"column":34},"end":{"line":273,"column":5}}]},"36":{"type":"branch","line":277,"loc":{"start":{"line":277,"column":10},"end":{"line":326,"column":3}},"locations":[{"start":{"line":277,"column":10},"end":{"line":326,"column":3}}]},"37":{"type":"branch","line":283,"loc":{"start":{"line":283,"column":6},"end":{"line":289,"column":14}},"locations":[{"start":{"line":283,"column":6},"end":{"line":289,"column":14}}]},"38":{"type":"branch","line":286,"loc":{"start":{"line":286,"column":25},"end":{"line":286,"column":45}},"locations":[{"start":{"line":286,"column":25},"end":{"line":286,"column":45}}]},"39":{"type":"branch","line":287,"loc":{"start":{"line":287,"column":23},"end":{"line":287,"column":37}},"locations":[{"start":{"line":287,"column":23},"end":{"line":287,"column":37}}]},"40":{"type":"branch","line":291,"loc":{"start":{"line":291,"column":6},"end":{"line":304,"column":14}},"locations":[{"start":{"line":291,"column":6},"end":{"line":304,"column":14}}]},"41":{"type":"branch","line":294,"loc":{"start":{"line":294,"column":26},"end":{"line":302,"column":11}},"locations":[{"start":{"line":294,"column":26},"end":{"line":302,"column":11}}]},"42":{"type":"branch","line":306,"loc":{"start":{"line":306,"column":6},"end":{"line":311,"column":14}},"locations":[{"start":{"line":306,"column":6},"end":{"line":311,"column":14}}]},"43":{"type":"branch","line":309,"loc":{"start":{"line":309,"column":27},"end":{"line":309,"column":45}},"locations":[{"start":{"line":309,"column":27},"end":{"line":309,"column":45}}]},"44":{"type":"branch","line":313,"loc":{"start":{"line":313,"column":6},"end":{"line":318,"column":14}},"locations":[{"start":{"line":313,"column":6},"end":{"line":318,"column":14}}]},"45":{"type":"branch","line":316,"loc":{"start":{"line":316,"column":37},"end":{"line":316,"column":111}},"locations":[{"start":{"line":316,"column":37},"end":{"line":316,"column":111}}]},"46":{"type":"branch","line":320,"loc":{"start":{"line":320,"column":6},"end":{"line":321,"column":71}},"locations":[{"start":{"line":320,"column":6},"end":{"line":321,"column":71}}]},"47":{"type":"branch","line":328,"loc":{"start":{"line":328,"column":9},"end":{"line":471,"column":3}},"locations":[{"start":{"line":328,"column":9},"end":{"line":471,"column":3}}]},"48":{"type":"branch","line":340,"loc":{"start":{"line":340,"column":44},"end":{"line":340,"column":64}},"locations":[{"start":{"line":340,"column":44},"end":{"line":340,"column":64}}]},"49":{"type":"branch","line":340,"loc":{"start":{"line":340,"column":52},"end":{"line":343,"column":7}},"locations":[{"start":{"line":340,"column":52},"end":{"line":343,"column":7}}]},"50":{"type":"branch","line":347,"loc":{"start":{"line":347,"column":26},"end":{"line":352,"column":5}},"locations":[{"start":{"line":347,"column":26},"end":{"line":352,"column":5}}]},"51":{"type":"branch","line":390,"loc":{"start":{"line":390,"column":25},"end":{"line":404,"column":5}},"locations":[{"start":{"line":390,"column":25},"end":{"line":404,"column":5}}]},"52":{"type":"branch","line":407,"loc":{"start":{"line":407,"column":16},"end":{"line":407,"column":56}},"locations":[{"start":{"line":407,"column":16},"end":{"line":407,"column":56}}]},"53":{"type":"branch","line":407,"loc":{"start":{"line":407,"column":56},"end":{"line":415,"column":5}},"locations":[{"start":{"line":407,"column":56},"end":{"line":415,"column":5}}]},"54":{"type":"branch","line":418,"loc":{"start":{"line":418,"column":41},"end":{"line":418,"column":75}},"locations":[{"start":{"line":418,"column":41},"end":{"line":418,"column":75}}]},"55":{"type":"branch","line":430,"loc":{"start":{"line":430,"column":30},"end":{"line":432,"column":5}},"locations":[{"start":{"line":430,"column":30},"end":{"line":432,"column":5}}]},"56":{"type":"branch","line":439,"loc":{"start":{"line":439,"column":58},"end":{"line":439,"column":66}},"locations":[{"start":{"line":439,"column":58},"end":{"line":439,"column":66}}]},"57":{"type":"branch","line":454,"loc":{"start":{"line":454,"column":17},"end":{"line":454,"column":70}},"locations":[{"start":{"line":454,"column":17},"end":{"line":454,"column":70}}]},"58":{"type":"branch","line":454,"loc":{"start":{"line":454,"column":70},"end":{"line":465,"column":5}},"locations":[{"start":{"line":454,"column":70},"end":{"line":465,"column":5}}]},"59":{"type":"branch","line":348,"loc":{"start":{"line":348,"column":47},"end":{"line":351,"column":7}},"locations":[{"start":{"line":348,"column":47},"end":{"line":351,"column":7}}]},"60":{"type":"branch","line":375,"loc":{"start":{"line":375,"column":42},"end":{"line":387,"column":5}},"locations":[{"start":{"line":375,"column":42},"end":{"line":387,"column":5}}]},"61":{"type":"branch","line":376,"loc":{"start":{"line":376,"column":36},"end":{"line":376,"column":55}},"locations":[{"start":{"line":376,"column":36},"end":{"line":376,"column":55}}]},"62":{"type":"branch","line":391,"loc":{"start":{"line":391,"column":46},"end":{"line":403,"column":7}},"locations":[{"start":{"line":391,"column":46},"end":{"line":403,"column":7}}]},"63":{"type":"branch","line":392,"loc":{"start":{"line":392,"column":38},"end":{"line":392,"column":58}},"locations":[{"start":{"line":392,"column":38},"end":{"line":392,"column":58}}]},"64":{"type":"branch","line":455,"loc":{"start":{"line":455,"column":92},"end":{"line":464,"column":9}},"locations":[{"start":{"line":455,"column":92},"end":{"line":464,"column":9}}]},"65":{"type":"branch","line":473,"loc":{"start":{"line":473,"column":9},"end":{"line":522,"column":3}},"locations":[{"start":{"line":473,"column":9},"end":{"line":522,"column":3}}]},"66":{"type":"branch","line":474,"loc":{"start":{"line":474,"column":85},"end":{"line":503,"column":7}},"locations":[{"start":{"line":474,"column":85},"end":{"line":503,"column":7}}]},"67":{"type":"branch","line":487,"loc":{"start":{"line":487,"column":38},"end":{"line":489,"column":7}},"locations":[{"start":{"line":487,"column":38},"end":{"line":489,"column":7}}]},"68":{"type":"branch","line":492,"loc":{"start":{"line":492,"column":28},"end":{"line":494,"column":7}},"locations":[{"start":{"line":492,"column":28},"end":{"line":494,"column":7}}]},"69":{"type":"branch","line":497,"loc":{"start":{"line":497,"column":25},"end":{"line":499,"column":7}},"locations":[{"start":{"line":497,"column":25},"end":{"line":499,"column":7}}]},"70":{"type":"branch","line":524,"loc":{"start":{"line":524,"column":9},"end":{"line":531,"column":3}},"locations":[{"start":{"line":524,"column":9},"end":{"line":531,"column":3}}]},"71":{"type":"branch","line":533,"loc":{"start":{"line":533,"column":9},"end":{"line":553,"column":3}},"locations":[{"start":{"line":533,"column":9},"end":{"line":553,"column":3}}]},"72":{"type":"branch","line":555,"loc":{"start":{"line":555,"column":9},"end":{"line":566,"column":3}},"locations":[{"start":{"line":555,"column":9},"end":{"line":566,"column":3}}]}},"b":{"0":[2],"1":[2],"2":[14],"3":[27],"4":[0],"5":[9],"6":[18],"7":[6],"8":[12],"9":[36],"10":[18],"11":[18],"12":[6],"13":[12],"14":[30],"15":[0],"16":[0],"17":[15],"18":[0],"19":[15],"20":[6],"21":[0],"22":[0],"23":[14],"24":[1],"25":[10],"26":[0],"27":[0],"28":[0],"29":[14],"30":[2],"31":[5],"32":[15],"33":[14],"34":[1],"35":[2],"36":[6],"37":[2],"38":[0],"39":[0],"40":[1],"41":[0],"42":[2],"43":[0],"44":[1],"45":[0],"46":[0],"47":[15],"48":[14],"49":[1],"50":[5],"51":[9],"52":[0],"53":[0],"54":[0],"55":[0],"56":[9],"57":[5],"58":[5],"59":[6],"60":[2],"61":[1],"62":[14],"63":[9],"64":[5],"65":[10],"66":[11],"67":[5],"68":[1],"69":[5],"70":[2],"71":[1],"72":[10]},"fnMap":{"0":{"name":"","decl":{"start":{"line":97,"column":19},"end":{"line":567,"column":1}},"loc":{"start":{"line":97,"column":19},"end":{"line":567,"column":1}},"line":97},"1":{"name":"OpenAPIStore","decl":{"start":{"line":105,"column":2},"end":{"line":112,"column":3}},"loc":{"start":{"line":105,"column":2},"end":{"line":112,"column":3}},"line":105},"2":{"name":"setTargetUrl","decl":{"start":{"line":114,"column":9},"end":{"line":116,"column":3}},"loc":{"start":{"line":114,"column":9},"end":{"line":116,"column":3}},"line":114},"3":{"name":"clear","decl":{"start":{"line":118,"column":9},"end":{"line":122,"column":3}},"loc":{"start":{"line":118,"column":9},"end":{"line":122,"column":3}},"line":118},"4":{"name":"deepMergeSchemas","decl":{"start":{"line":124,"column":10},"end":{"line":158,"column":3}},"loc":{"start":{"line":124,"column":10},"end":{"line":158,"column":3}},"line":124},"5":{"name":"generateJsonSchema","decl":{"start":{"line":160,"column":10},"end":{"line":215,"column":3}},"loc":{"start":{"line":160,"column":10},"end":{"line":215,"column":3}},"line":160},"6":{"name":"recordHAREntry","decl":{"start":{"line":217,"column":10},"end":{"line":264,"column":3}},"loc":{"start":{"line":217,"column":10},"end":{"line":264,"column":3}},"line":217},"7":{"name":"buildQueryString","decl":{"start":{"line":266,"column":10},"end":{"line":275,"column":3}},"loc":{"start":{"line":266,"column":10},"end":{"line":275,"column":3}},"line":266},"8":{"name":"addSecurityScheme","decl":{"start":{"line":277,"column":10},"end":{"line":326,"column":3}},"loc":{"start":{"line":277,"column":10},"end":{"line":326,"column":3}},"line":277},"9":{"name":"recordEndpoint","decl":{"start":{"line":328,"column":9},"end":{"line":471,"column":3}},"loc":{"start":{"line":328,"column":9},"end":{"line":471,"column":3}},"line":328},"10":{"name":"getOpenAPISpec","decl":{"start":{"line":473,"column":9},"end":{"line":522,"column":3}},"loc":{"start":{"line":473,"column":9},"end":{"line":522,"column":3}},"line":473},"11":{"name":"getOpenAPISpecAsYAML","decl":{"start":{"line":524,"column":9},"end":{"line":531,"column":3}},"loc":{"start":{"line":524,"column":9},"end":{"line":531,"column":3}},"line":524},"12":{"name":"saveOpenAPISpec","decl":{"start":{"line":533,"column":9},"end":{"line":553,"column":3}},"loc":{"start":{"line":533,"column":9},"end":{"line":553,"column":3}},"line":533},"13":{"name":"generateHAR","decl":{"start":{"line":555,"column":9},"end":{"line":566,"column":3}},"loc":{"start":{"line":555,"column":9},"end":{"line":566,"column":3}},"line":555}},"f":{"0":2,"1":2,"2":0,"3":14,"4":27,"5":30,"6":15,"7":15,"8":6,"9":15,"10":10,"11":2,"12":1,"13":10}} -} diff --git a/coverage/favicon.png b/coverage/favicon.png deleted file mode 100644 index c1525b81..00000000 Binary files a/coverage/favicon.png and /dev/null differ diff --git a/coverage/index.html b/coverage/index.html deleted file mode 100644 index e08a5eca..00000000 --- a/coverage/index.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 52.16% - Statements - 374/717 -
- - -
- 71.42% - Branches - 60/84 -
- - -
- 94.44% - Functions - 17/18 -
- - -
- 52.16% - Lines - 374/717 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
src -
-
0%0/264100%2/2100%2/20%0/264
src/middleware -
-
60.6%40/6644.44%4/9100%2/260.6%40/66
src/store -
-
86.3%334/38773.97%54/7392.85%13/1486.3%334/387
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/prettify.css b/coverage/prettify.css deleted file mode 100644 index b317a7cd..00000000 --- a/coverage/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.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} diff --git a/coverage/prettify.js b/coverage/prettify.js deleted file mode 100644 index b3225238..00000000 --- a/coverage/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* 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;V122)){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;arat[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=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=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=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=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*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\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=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]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\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"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png deleted file mode 100644 index 6ed68316..00000000 Binary files a/coverage/sort-arrow-sprite.png and /dev/null differ diff --git a/coverage/sorter.js b/coverage/sorter.js deleted file mode 100644 index 2bb296a8..00000000 --- a/coverage/sorter.js +++ /dev/null @@ -1,196 +0,0 @@ -/* 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 + ''; - } - } - 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); diff --git a/coverage/src/cli.ts.html b/coverage/src/cli.ts.html deleted file mode 100644 index 8c1f8988..00000000 --- a/coverage/src/cli.ts.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - Code coverage report for src/cli.ts - - - - - - - - - -
-
-

All files / src cli.ts

-
- -
- 0% - Statements - 0/28 -
- - -
- 100% - Branches - 1/1 -
- - -
- 100% - Functions - 1/1 -
- - -
- 0% - Lines - 0/28 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
#!/usr/bin/env node
- 
-import { Command } from 'commander';
-import chalk from 'chalk';
-import { startServers } from './server.js';
- 
-const program = new Command();
- 
-console.log('Starting Arbiter...');
- 
-program
-  .name('arbiter')
-  .description('API proxy with OpenAPI generation and HAR export capabilities')
-  .version('1.0.0')
-  .requiredOption('-t, --target <url>', 'target API URL to proxy to')
-  .option('-p, --port <number>', 'port to run the proxy server on', '8080')
-  .option('-d, --docs-port <number>', 'port to run the documentation server on', '9000')
-  .option('-k, --key <string>', 'API key to add to proxied requests')
-  .option('--docs-only', 'run only the documentation server')
-  .option('--proxy-only', 'run only the proxy server')
-  .option('-v, --verbose', 'enable verbose logging')
-  .parse(process.argv);
- 
-const options = program.opts();
- 
-// Start the servers
-startServers({
-  target: options.target,
-  proxyPort: parseInt(options.port),
-  docsPort: parseInt(options.docsPort),
-  apiKey: options.key,
-  verbose: options.verbose
-}).catch((error) => {
-  console.error(chalk.red('Failed to start servers:'), error);
-  process.exit(1);
-});
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html deleted file mode 100644 index bb770d85..00000000 --- a/coverage/src/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src - - - - - - - - - -
-
-

All files src

-
- -
- 0% - Statements - 0/264 -
- - -
- 100% - Branches - 2/2 -
- - -
- 100% - Functions - 2/2 -
- - -
- 0% - Lines - 0/264 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
cli.ts -
-
0%0/28100%1/1100%1/10%0/28
server.ts -
-
0%0/236100%1/1100%1/10%0/236
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/middleware/apiDocGenerator.ts.html b/coverage/src/middleware/apiDocGenerator.ts.html deleted file mode 100644 index b0a4b605..00000000 --- a/coverage/src/middleware/apiDocGenerator.ts.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - Code coverage report for src/middleware/apiDocGenerator.ts - - - - - - - - - -
-
-

All files / src/middleware apiDocGenerator.ts

-
- -
- 0% - Statements - 0/18 -
- - -
- 100% - Branches - 1/1 -
- - -
- 100% - Functions - 1/1 -
- - -
- 0% - Lines - 0/18 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { Context } from 'hono';
-import { openApiStore } from '../store/openApiStore.js';
- 
-export const apiDocGenerator = async (c: Context, next: () => Promise<void>) => {
-  await next();
- 
-  // Record the API call in OpenAPI format
-  openApiStore.recordEndpoint(
-    c.req.path,
-    c.req.method.toLowerCase(),
-    {
-      query: Object.fromEntries(new URL(c.req.url).searchParams),
-      body: await c.req.json().catch(() => null),
-      contentType: c.req.header('content-type') || 'application/json',
-    },
-    {
-      status: c.res.status,
-      body: await c.res.clone().json().catch(() => null),
-      contentType: c.res.headers.get('content-type') || 'application/json',
-    }
-  );
-}; 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/middleware/harRecorder.ts.html b/coverage/src/middleware/harRecorder.ts.html deleted file mode 100644 index 009b5e26..00000000 --- a/coverage/src/middleware/harRecorder.ts.html +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - Code coverage report for src/middleware/harRecorder.ts - - - - - - - - - -
-
-

All files / src/middleware harRecorder.ts

-
- -
- 83.33% - Statements - 40/48 -
- - -
- 37.5% - Branches - 3/8 -
- - -
- 100% - Functions - 1/1 -
- - -
- 83.33% - Lines - 40/48 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -  -  -4x -4x -  -  -  -  -  -  -  -  -  -4x -4x -4x -2x -2x -  -  -4x -4x -8x -8x -8x -4x -  -  -4x -  -  -4x -  -  -4x -4x -4x -4x -  -  -  -  -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -  -  -4x -4x
import { Context, Next } from 'hono';
-import { openApiStore } from '../store/openApiStore.js';
- 
-interface HAREntry {
-  startedDateTime: string;
-  time: number;
-  request: {
-    method: string;
-    url: string;
-    httpVersion: string;
-    headers: Array<{ name: string; value: string }>;
-    queryString: Array<{ name: string; value: string }>;
-    postData?: {
-      mimeType: string;
-      text: string;
-    };
-  };
-  response: {
-    status: number;
-    statusText: string;
-    httpVersion: string;
-    headers: Array<{ name: string; value: string }>;
-    content: {
-      size: number;
-      mimeType: string;
-      text: string;
-    };
-  };
-}
- 
-export async function harRecorder(c: Context, next: Next) {
-  const startTime = Date.now();
- 
-  // Get request body if present
-  let requestBody: any;
-  if (c.req.method !== 'GET' && c.req.method !== 'HEAD') {
-    try {
-      requestBody = await c.req.json();
-    } catch (e) {
-      // Body might not be JSON
-      requestBody = await c.req.text();
-    }
-  }
- 
-  // Get query parameters from URL
-  const url = new URL(c.req.url);
-  const queryParams: Record<string, string> = {};
-  for (const [key, value] of url.searchParams.entries()) {
-    queryParams[key] = value;
-  }
- 
-  // Get all request headers
-  const requestHeaders: Record<string, string> = {};
-  Object.entries(c.req.header()).forEach(([key, value]) => {
-    if (typeof value === 'string') {
-      requestHeaders[key] = value;
-    }
-  });
- 
-  // Call next middleware
-  await next();
- 
-  // Calculate response time
-  const responseTime = Date.now() - startTime;
- 
-  // Get response body
-  let responseBody: any;
-  try {
-    responseBody = await c.res.clone().json();
-  } catch (e) {
-    responseBody = await c.res.clone().text();
-  }
- 
-  // Record the request/response in OpenAPI format
-  openApiStore.recordEndpoint(
-    c.req.path,
-    c.req.method.toLowerCase(),
-    {
-      query: queryParams,
-      body: requestBody,
-      contentType: c.req.header('content-type') || 'application/json',
-      headers: requestHeaders
-    },
-    {
-      status: c.res.status,
-      body: responseBody,
-      contentType: c.res.headers.get('content-type') || 'application/json',
-      headers: Object.fromEntries(c.res.headers.entries())
-    }
-  );
- 
-  // Set HAR data in context
-  c.set('har', openApiStore.generateHAR());
-} 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/middleware/index.html b/coverage/src/middleware/index.html deleted file mode 100644 index 4c8d7f53..00000000 --- a/coverage/src/middleware/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for src/middleware - - - - - - - - - -
-
-

All files src/middleware

-
- -
- 60.6% - Statements - 40/66 -
- - -
- 44.44% - Branches - 4/9 -
- - -
- 100% - Functions - 2/2 -
- - -
- 60.6% - Lines - 40/66 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
apiDocGenerator.ts -
-
0%0/18100%1/1100%1/10%0/18
harRecorder.ts -
-
83.33%40/4837.5%3/8100%1/183.33%40/48
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/server.ts.html b/coverage/src/server.ts.html deleted file mode 100644 index dde9ae56..00000000 --- a/coverage/src/server.ts.html +++ /dev/null @@ -1,1066 +0,0 @@ - - - - - - Code coverage report for src/server.ts - - - - - - - - - -
-
-

All files / src server.ts

-
- -
- 0% - Statements - 0/236 -
- - -
- 100% - Branches - 1/1 -
- - -
- 100% - Functions - 1/1 -
- - -
- 0% - Lines - 0/236 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { serve } from '@hono/node-server';
-import { Hono } from 'hono';
-import { logger } from 'hono/logger';
-import { cors } from 'hono/cors';
-import { prettyJSON } from 'hono/pretty-json';
-import httpProxy from 'http-proxy';
-import { Context } from 'hono';
-import { openApiStore } from './store/openApiStore.js';
-import { IncomingMessage, ServerResponse, createServer, Server } from 'node:http';
-import { Agent } from 'node:https';
-import chalk from 'chalk';
- 
-export interface ServerOptions {
-  target: string;
-  proxyPort: number;
-  docsPort: number;
-  apiKey?: string;
-  verbose?: boolean;
-}
- 
-export async function startServers(options: ServerOptions): Promise<{ proxyServer: Server; docsServer: Server }> {
-  // Set the target URL in the OpenAPI store
-  openApiStore.setTargetUrl(options.target);
- 
-  // Create two separate Hono apps
-  const proxyApp = new Hono();
-  const docsApp = new Hono();
- 
-  // Create proxy server
-  const proxy = httpProxy.createProxyServer({
-    changeOrigin: true,
-    secure: false,
-    selfHandleResponse: true,
-    target: options.target,
-    headers: {
-      'Host': new URL(options.target).host
-    },
-    agent: new Agent({
-      rejectUnauthorized: false
-    })
-  });
- 
-  // Set up error handlers
-  proxy.on('error', (err) => {
-    console.error('Proxy error:', err);
-  });
- 
-  proxy.on('proxyReq', (proxyReq, req, res) => {
-    // Ensure we're using the correct protocol
-    proxyReq.protocol = new URL(options.target).protocol;
-  });
- 
-  // Middleware for both apps
-  if (options.verbose) {
-    proxyApp.use('*', logger());
-    docsApp.use('*', logger());
-  }
-  proxyApp.use('*', cors());
-  proxyApp.use('*', prettyJSON());
-  docsApp.use('*', cors());
-  docsApp.use('*', prettyJSON());
- 
-  // Documentation endpoints
-  docsApp.get('/docs', async (c: Context) => {
-    const spec = openApiStore.getOpenAPISpec();
-    return c.html(`
-      <!DOCTYPE html>
-      <html>
-        <head>
-          <title>API Documentation</title>
-          <meta charset="utf-8" />
-          <meta name="viewport" content="width=device-width, initial-scale=1" />
-        </head>
-        <body>
-          <script
-            id="api-reference"
-            data-url="/openapi.json"
-            data-proxy-url="https://proxy.scalar.com"></script>
- 
-          <script>
-            var configuration = {
-              theme: 'light',
-              title: 'API Documentation'
-            }
- 
-            document.getElementById('api-reference').dataset.configuration =
-              JSON.stringify(configuration)
-          </script>
- 
-          <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
-        </body>
-      </html>
-    `);
-  });
-  docsApp.get('/openapi.json', (c: Context) => {
-    return c.json(openApiStore.getOpenAPISpec());
-  });
-  docsApp.get('/openapi.yaml', (c: Context) => {
-    return c.text(openApiStore.getOpenAPISpecAsYAML());
-  });
-  docsApp.get('/har', (c: Context) => {
-    return c.json(openApiStore.generateHAR());
-  });
- 
-  // Proxy all requests
-  proxyApp.all('*', async (c: Context) => {
-    let requestBody: any;
-    let responseBody: any;
- 
-    // Get request body if present
-    if (c.req.method !== 'GET' && c.req.method !== 'HEAD') {
-      try {
-        requestBody = await c.req.json();
-      } catch (e) {
-        // Body might not be JSON
-        requestBody = await c.req.text();
-      }
-    }
- 
-    try {
-      // Create a new request object with the target URL
-      const targetUrl = new URL(c.req.path, options.target);
-      // Copy query parameters
-      const originalUrl = new URL(c.req.url);
-      originalUrl.searchParams.forEach((value, key) => {
-        targetUrl.searchParams.append(key, value);
-      });
- 
-      const proxyReq = new Request(targetUrl.toString(), {
-        method: c.req.method,
-        headers: new Headers({
-          'content-type': c.req.header('content-type') || 'application/json',
-          'accept': c.req.header('accept') || 'application/json',
-          ...Object.fromEntries(
-            Object.entries(c.req.header())
-              .filter(([key]) => !['content-type', 'accept'].includes(key.toLowerCase()))
-          ),
-        }),
-        body: c.req.method !== 'GET' && c.req.method !== 'HEAD' ? requestBody : undefined,
-      });
- 
-      // Forward the request to the target server
-      const proxyRes = await fetch(proxyReq);
- 
-      // Get response body
-      const contentType = proxyRes.headers.get('content-type') || '';
-      if (contentType.includes('application/json')) {
-        responseBody = await proxyRes.json();
-      } else {
-        responseBody = await proxyRes.text();
-      }
- 
-      // Record the API call in OpenAPI format
-      openApiStore.recordEndpoint(
-        c.req.path,
-        c.req.method.toLowerCase(),
-        {
-          query: Object.fromEntries(new URL(c.req.url).searchParams),
-          body: requestBody,
-          contentType: c.req.header('content-type') || 'application/json',
-          headers: Object.fromEntries(Object.entries(c.req.header()))
-        },
-        {
-          status: proxyRes.status,
-          body: responseBody,
-          contentType: proxyRes.headers.get('content-type') || 'application/json',
-          headers: Object.fromEntries(proxyRes.headers.entries())
-        }
-      );
- 
-      // Create a new response with the correct content type and body
-      return new Response(JSON.stringify(responseBody), {
-        status: proxyRes.status,
-        headers: Object.fromEntries(proxyRes.headers.entries())
-      });
-    } catch (error: any) {
-      console.error('Proxy request failed:', error);
-      return c.json({ error: 'Proxy error', details: error.message }, 500);
-    }
-  });
- 
-  // Add API key if provided
-  if (options.apiKey) {
-    proxy.on('proxyReq', (proxyReq) => {
-      proxyReq.setHeader('Authorization', `Bearer ${options.apiKey}`);
-    });
-  }
- 
-  // Function to check if a port is available
-  async function isPortAvailable(port: number): Promise<boolean> {
-    return new Promise((resolve) => {
-      const server = createServer()
-        .once('error', () => {
-          resolve(false);
-        })
-        .once('listening', () => {
-          server.close();
-          resolve(true);
-        })
-        .listen(port);
-    });
-  }
- 
-  // Function to find an available port
-  async function findAvailablePort(startPort: number): Promise<number> {
-    let port = startPort;
-    while (!(await isPortAvailable(port))) {
-      port++;
-    }
-    return port;
-  }
- 
-  // Start servers
-  const availableProxyPort = await findAvailablePort(options.proxyPort);
-  const availableDocsPort = await findAvailablePort(options.docsPort);
- 
-  if (availableProxyPort !== options.proxyPort) {
-    console.log(chalk.yellow(`Port ${options.proxyPort} is in use, using port ${availableProxyPort} instead`));
-  }
-  if (availableDocsPort !== options.docsPort) {
-    console.log(chalk.yellow(`Port ${options.docsPort} is in use, using port ${availableDocsPort} instead`));
-  }
- 
-  console.log(chalk.blue(`Starting proxy server on port ${availableProxyPort}...`));
-  console.log(chalk.gray(`Proxying requests to: ${options.target}`));
-  console.log(chalk.blue(`Starting documentation server on port ${availableDocsPort}...`));
- 
-  const proxyServer = createServer(async (req, res) => {
-    try {
-      const url = new URL(req.url || '/', `http://localhost:${availableProxyPort}`);
-      const request = new Request(url.toString(), {
-        method: req.method || 'GET',
-        headers: req.headers as Record<string, string>,
-        body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined,
-      });
- 
-      const response = await proxyApp.fetch(request);
-      res.statusCode = response.status;
-      res.statusMessage = response.statusText;
- 
-      // Copy all headers from the response
-      for (const [key, value] of response.headers.entries()) {
-        res.setHeader(key, value);
-      }
- 
-      // Stream the response body
-      if (response.body) {
-        const reader = response.body.getReader();
-        while (true) {
-          const { done, value } = await reader.read();
-          if (done) break;
-          res.write(value);
-        }
-        res.end();
-      } else {
-        res.end();
-      }
-    } catch (error: any) {
-      console.error('Proxy request failed:', error);
-      res.statusCode = 500;
-      res.end(JSON.stringify({ error: 'Proxy error', details: error.message }));
-    }
-  });
- 
-  const docsServer = createServer(async (req, res) => {
-    try {
-      const url = new URL(req.url || '/', `http://localhost:${availableDocsPort}`);
-      const request = new Request(url.toString(), {
-        method: req.method || 'GET',
-        headers: req.headers as Record<string, string>,
-        body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined,
-      });
- 
-      const response = await docsApp.fetch(request);
-      res.statusCode = response.status;
-      res.statusMessage = response.statusText;
- 
-      for (const [key, value] of response.headers.entries()) {
-        res.setHeader(key, value);
-      }
- 
-      if (response.body) {
-        const reader = response.body.getReader();
-        while (true) {
-          const { done, value } = await reader.read();
-          if (done) break;
-          res.write(value);
-        }
-      }
-      res.end();
-    } catch (error: any) {
-      console.error('Documentation request failed:', error);
-      res.statusCode = 500;
-      res.end(JSON.stringify({ error: 'Documentation error', details: error.message }));
-    }
-  });
- 
-  await new Promise<void>((resolve, reject) => {
-    proxyServer.once('error', reject);
-    proxyServer.listen(availableProxyPort, '0.0.0.0', () => {
-      console.log(chalk.green(`✓ Proxy server running on port ${availableProxyPort}`));
-      resolve();
-    });
-  });
- 
-  await new Promise<void>((resolve, reject) => {
-    docsServer.once('error', reject);
-    docsServer.listen(availableDocsPort, '0.0.0.0', () => {
-      console.log(chalk.green(`✓ Documentation server running on port ${availableDocsPort}`));
-      resolve();
-    });
-  });
- 
-  // Print startup message
-  console.log('\n' + chalk.green('Arbiter is running! 🚀'));
-  console.log('\n' + chalk.bold('Proxy Server:'));
-  console.log(chalk.cyan(`  URL: http://localhost:${availableProxyPort}`));
-  console.log(chalk.gray(`  Target: ${options.target}`));
-  console.log('\n' + chalk.bold('Documentation:'));
-  console.log(chalk.cyan(`  API Reference: http://localhost:${availableDocsPort}/docs`));
-  console.log('\n' + chalk.bold('Exports:'));
-  console.log(chalk.cyan(`  HAR Export: http://localhost:${availableDocsPort}/har`));
-  console.log(chalk.cyan(`  OpenAPI JSON: http://localhost:${availableDocsPort}/openapi.json`));
-  console.log(chalk.cyan(`  OpenAPI YAML: http://localhost:${availableDocsPort}/openapi.yaml`));
-  console.log('\n' + chalk.yellow('Press Ctrl+C to stop'));
- 
-  return { proxyServer, docsServer };
-} 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/store/index.html b/coverage/src/store/index.html deleted file mode 100644 index 0f99e154..00000000 --- a/coverage/src/store/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for src/store - - - - - - - - - -
-
-

All files src/store

-
- -
- 86.3% - Statements - 334/387 -
- - -
- 73.97% - Branches - 54/73 -
- - -
- 92.85% - Functions - 13/14 -
- - -
- 86.3% - Lines - 334/387 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
openApiStore.ts -
-
86.3%334/38773.97%54/7392.85%13/1486.3%334/387
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/src/store/openApiStore.ts.html b/coverage/src/store/openApiStore.ts.html deleted file mode 100644 index b49d7411..00000000 --- a/coverage/src/store/openApiStore.ts.html +++ /dev/null @@ -1,1789 +0,0 @@ - - - - - - Code coverage report for src/store/openApiStore.ts - - - - - - - - - -
-
-

All files / src/store openApiStore.ts

-
- -
- 86.3% - Statements - 334/387 -
- - -
- 73.97% - Branches - 54/73 -
- - -
- 92.85% - Functions - 13/14 -
- - -
- 86.3% - Lines - 334/387 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -269 -270 -271 -272 -273 -274 -275 -276 -277 -278 -279 -280 -281 -282 -283 -284 -285 -286 -287 -288 -289 -290 -291 -292 -293 -294 -295 -296 -297 -298 -299 -300 -301 -302 -303 -304 -305 -306 -307 -308 -309 -310 -311 -312 -313 -314 -315 -316 -317 -318 -319 -320 -321 -322 -323 -324 -325 -326 -327 -328 -329 -330 -331 -332 -333 -334 -335 -336 -337 -338 -339 -340 -341 -342 -343 -344 -345 -346 -347 -348 -349 -350 -351 -352 -353 -354 -355 -356 -357 -358 -359 -360 -361 -362 -363 -364 -365 -366 -367 -368 -369 -370 -371 -372 -373 -374 -375 -376 -377 -378 -379 -380 -381 -382 -383 -384 -385 -386 -387 -388 -389 -390 -391 -392 -393 -394 -395 -396 -397 -398 -399 -400 -401 -402 -403 -404 -405 -406 -407 -408 -409 -410 -411 -412 -413 -414 -415 -416 -417 -418 -419 -420 -421 -422 -423 -424 -425 -426 -427 -428 -429 -430 -431 -432 -433 -434 -435 -436 -437 -438 -439 -440 -441 -442 -443 -444 -445 -446 -447 -448 -449 -450 -451 -452 -453 -454 -455 -456 -457 -458 -459 -460 -461 -462 -463 -464 -465 -466 -467 -468 -469 -470 -471 -472 -473 -474 -475 -476 -477 -478 -479 -480 -481 -482 -483 -484 -485 -486 -487 -488 -489 -490 -491 -492 -493 -494 -495 -496 -497 -498 -499 -500 -501 -502 -503 -504 -505 -506 -507 -508 -509 -510 -511 -512 -513 -514 -515 -516 -517 -518 -519 -520 -521 -522 -523 -524 -525 -526 -527 -528 -529 -530 -531 -532 -533 -534 -535 -536 -537 -538 -539 -540 -541 -542 -543 -544 -545 -546 -547 -548 -549 -550 -551 -552 -553 -554 -555 -556 -557 -558 -559 -560 -561 -562 -563 -564 -565 -566 -567 -568 -5691x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -2x -2x -2x -2x -2x -2x -  -2x -2x -2x -2x -2x -2x -2x -2x -  -2x -  -  -  -2x -14x -14x -14x -14x -  -2x -27x -27x -  -  -27x -6x -6x -  -6x -18x -18x -18x -6x -18x -  -12x -12x -18x -18x -6x -  -6x -6x -6x -6x -6x -6x -  -  -12x -12x -12x -12x -27x -  -2x -30x -30x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -30x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -  -  -15x -15x -15x -15x -15x -15x -15x -15x -15x -  -15x -30x -30x -30x -30x -  -2x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -14x -14x -15x -15x -15x -2x -2x -15x -15x -  -  -15x -15x -15x -15x -15x -15x -15x -15x -5x -5x -15x -15x -15x -15x -15x -15x -15x -15x -  -15x -15x -  -2x -15x -14x -14x -1x -1x -2x -1x -1x -15x -  -2x -  -6x -6x -  -6x -6x -2x -2x -2x -2x -2x -2x -  -6x -1x -1x -1x -  -  -  -  -  -  -  -  -1x -1x -  -6x -2x -2x -2x -2x -2x -  -6x -1x -1x -1x -1x -1x -  -6x -  -6x -  -6x -6x -6x -  -2x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -15x -1x -1x -1x -15x -  -  -15x -5x -6x -6x -5x -5x -  -  -15x -  -  -15x -15x -  -  -  -  -  -  -  -  -  -  -  -  -15x -  -  -15x -2x -2x -2x -2x -2x -2x -2x -2x -2x -2x -2x -15x -  -  -15x -9x -14x -14x -14x -14x -14x -14x -14x -14x -14x -14x -14x -9x -9x -  -  -15x -  -  -  -  -  -  -  -  -  -  -15x -  -  -15x -15x -15x -15x -15x -15x -  -  -15x -15x -  -  -  -  -15x -  -  -15x -15x -  -  -15x -15x -  -  -15x -  -  -15x -15x -15x -  -  -15x -5x -5x -5x -5x -5x -5x -5x -5x -5x -5x -5x -  -15x -  -  -15x -15x -  -2x -10x -11x -  -11x -11x -11x -  -11x -11x -11x -11x -  -  -11x -5x -5x -  -  -11x -1x -1x -  -  -11x -5x -5x -  -11x -11x -10x -  -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -  -10x -10x -  -2x -2x -2x -2x -2x -2x -2x -2x -  -2x -1x -1x -  -  -1x -1x -1x -  -  -1x -1x -1x -1x -  -  -1x -1x -1x -1x -1x -  -2x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -10x -2x -  -1x
import fs from 'fs';
-import path from 'path';
-import { stringify } from 'yaml';
-import type {
-  OpenAPI,
-  OpenAPIV3_1
-} from 'openapi-types';
- 
-interface SecurityInfo {
-  type: 'apiKey' | 'oauth2' | 'http' | 'openIdConnect';
-  scheme?: 'bearer' | 'basic' | 'digest';
-  name?: string;
-  in?: 'header' | 'query' | 'cookie';
-  flows?: {
-    implicit?: {
-      authorizationUrl: string;
-      scopes: Record<string, string>;
-    };
-    authorizationCode?: {
-      authorizationUrl: string;
-      tokenUrl: string;
-      scopes: Record<string, string>;
-    };
-    clientCredentials?: {
-      tokenUrl: string;
-      scopes: Record<string, string>;
-    };
-    password?: {
-      tokenUrl: string;
-      scopes: Record<string, string>;
-    };
-  };
-  openIdConnectUrl?: string;
-}
- 
-interface RequestInfo {
-  query: Record<string, string>;
-  body: any;
-  contentType: string;
-  headers?: Record<string, string>;
-  security?: SecurityInfo[];
-}
- 
-interface ResponseInfo {
-  status: number;
-  body: any;
-  contentType: string;
-  headers?: Record<string, string>;
-}
- 
-interface EndpointInfo {
-  path: string;
-  method: string;
-  responses: {
-    [key: number]: OpenAPIV3_1.ResponseObject;
-  };
-  parameters: OpenAPIV3_1.ParameterObject[];
-  requestBody?: OpenAPIV3_1.RequestBodyObject;
-  security?: OpenAPIV3_1.SecurityRequirementObject[];
-}
- 
-interface HAREntry {
-  startedDateTime: string;
-  time: number;
-  request: {
-    method: string;
-    url: string;
-    httpVersion: string;
-    headers: Array<{ name: string; value: string }>;
-    queryString: Array<{ name: string; value: string }>;
-    postData?: {
-      mimeType: string;
-      text: string;
-    };
-  };
-  response: {
-    status: number;
-    statusText: string;
-    httpVersion: string;
-    headers: Array<{ name: string; value: string }>;
-    content: {
-      size: number;
-      mimeType: string;
-      text: string;
-    };
-  };
-}
- 
-type PathItemObject = {
-  [method: string]: OpenAPIV3_1.OperationObject;
-};
- 
-type PathsObject = {
-  [path: string]: PathItemObject;
-};
- 
-class OpenAPIStore {
-  private endpoints: Map<string, EndpointInfo>;
-  private harEntries: HAREntry[];
-  private targetUrl: string;
-  private examples: Map<any, any[]>;
-  private schemaCache: Map<string, OpenAPIV3_1.SchemaObject[]>;
-  private securitySchemes: Map<string, OpenAPIV3_1.SecuritySchemeObject>;
- 
-  constructor(targetUrl: string = 'http://localhost:8080') {
-    this.endpoints = new Map();
-    this.harEntries = [];
-    this.targetUrl = targetUrl;
-    this.examples = new Map();
-    this.schemaCache = new Map();
-    this.securitySchemes = new Map();
-  }
- 
-  public setTargetUrl(url: string): void {
-    this.targetUrl = url;
-  }
- 
-  public clear(): void {
-    this.endpoints.clear();
-    this.harEntries = [];
-    this.examples.clear();
-  }
- 
-  private deepMergeSchemas(schemas: OpenAPIV3_1.SchemaObject[]): OpenAPIV3_1.SchemaObject {
-    if (schemas.length === 0) return { type: 'object' };
-    if (schemas.length === 1) return schemas[0];
- 
-    // If all schemas are objects, merge their properties
-    if (schemas.every(s => s.type === 'object')) {
-      const mergedProperties: Record<string, OpenAPIV3_1.SchemaObject> = {};
-      const mergedRequired: string[] = [];
- 
-      schemas.forEach(schema => {
-        if (schema.properties) {
-          Object.entries(schema.properties).forEach(([key, value]) => {
-            if (!mergedProperties[key]) {
-              mergedProperties[key] = value;
-            } else {
-              // If property exists, merge its schemas
-              mergedProperties[key] = this.deepMergeSchemas([mergedProperties[key], value]);
-            }
-          });
-        }
-      });
- 
-      return {
-        type: 'object',
-        properties: mergedProperties,
-        example: schemas[0].example // Keep the first example
-      };
-    }
- 
-    // If schemas are different types, use oneOf
-    return {
-      type: 'object',
-      oneOf: schemas
-    };
-  }
- 
-  private generateJsonSchema(obj: any): OpenAPIV3_1.SchemaObject {
-    if (obj === null) return { type: 'null' };
-    if (Array.isArray(obj)) {
-      if (obj.length === 0) return { type: 'array', items: { type: 'object' } };
-      
-      // Generate schemas for all items
-      const itemSchemas = obj.map(item => this.generateJsonSchema(item));
-      
-      // If all items have the same schema, use that
-      if (itemSchemas.every(s => JSON.stringify(s) === JSON.stringify(itemSchemas[0]))) {
-        return {
-          type: 'array',
-          items: itemSchemas[0],
-          example: obj
-        };
-      }
-      
-      // If items have different schemas, use oneOf
-      return {
-        type: 'array',
-        items: {
-          type: 'object',
-          oneOf: itemSchemas
-        },
-        example: obj
-      };
-    }
-    
-    if (typeof obj === 'object') {
-      const properties: Record<string, OpenAPIV3_1.SchemaObject> = {};
-      for (const [key, value] of Object.entries(obj)) {
-        properties[key] = this.generateJsonSchema(value);
-      }
-      return {
-        type: 'object',
-        properties,
-        example: obj
-      };
-    }
-    
-    // Map JavaScript types to OpenAPI types
-    const typeMap: Record<string, OpenAPIV3_1.NonArraySchemaObjectType> = {
-      'string': 'string',
-      'number': 'number',
-      'boolean': 'boolean',
-      'bigint': 'integer',
-      'symbol': 'string',
-      'undefined': 'string',
-      'function': 'string'
-    };
-    
-    return { 
-      type: typeMap[typeof obj] || 'string',
-      example: obj
-    };
-  }
- 
-  private recordHAREntry(
-    path: string,
-    method: string,
-    request: RequestInfo,
-    response: ResponseInfo
-  ): void {
-    const now = new Date();
-    const entry: HAREntry = {
-      startedDateTime: now.toISOString(),
-      time: 0,
-      request: {
-        method: method.toUpperCase(),
-        url: `http://localhost:3000${path}${this.buildQueryString(request.query)}`,
-        httpVersion: 'HTTP/1.1',
-        headers: Object.entries(request.headers || {})
-          .map(([name, value]) => ({ 
-            name: name.toLowerCase(), // Normalize header names
-            value: String(value) // Ensure value is a string
-          })),
-        queryString: Object.entries(request.query || {})
-          .map(([name, value]) => ({ 
-            name, 
-            value: String(value) // Ensure value is a string
-          })),
-        postData: request.body ? {
-          mimeType: request.contentType,
-          text: JSON.stringify(request.body)
-        } : undefined
-      },
-      response: {
-        status: response.status,
-        statusText: response.status === 200 ? 'OK' : 'Error',
-        httpVersion: 'HTTP/1.1',
-        headers: Object.entries(response.headers || {})
-          .map(([name, value]) => ({ 
-            name: name.toLowerCase(), // Normalize header names
-            value: String(value) // Ensure value is a string
-          })),
-        content: {
-          size: response.body ? JSON.stringify(response.body).length : 0,
-          mimeType: response.contentType || 'application/json',
-          text: response.body ? JSON.stringify(response.body) : ''
-        }
-      }
-    };
- 
-    this.harEntries.push(entry);
-  }
- 
-  private buildQueryString(query: Record<string, string>): string {
-    if (!query || Object.keys(query).length === 0) {
-      return '';
-    }
-    const params = new URLSearchParams();
-    Object.entries(query).forEach(([key, value]) => {
-      params.append(key, value);
-    });
-    return `?${params.toString()}`;
-  }
- 
-  private addSecurityScheme(security: SecurityInfo): string {
-    // Use a consistent name based on the type with an underscore suffix
-    const schemeName = `${security.type}_`;
-    let scheme: OpenAPIV3_1.SecuritySchemeObject;
- 
-    switch (security.type) {
-      case 'apiKey':
-        scheme = {
-          type: 'apiKey',
-          name: security.name || 'X-API-Key',
-          in: security.in || 'header'
-        };
-        break;
- 
-      case 'oauth2':
-        scheme = {
-          type: 'oauth2',
-          flows: security.flows || {
-            implicit: {
-              authorizationUrl: 'https://example.com/oauth/authorize',
-              scopes: {
-                'read': 'Read access',
-                'write': 'Write access'
-              }
-            }
-          }
-        };
-        break;
- 
-      case 'http':
-        scheme = {
-          type: 'http',
-          scheme: security.scheme || 'bearer'
-        };
-        break;
- 
-      case 'openIdConnect':
-        scheme = {
-          type: 'openIdConnect',
-          openIdConnectUrl: security.openIdConnectUrl || 'https://example.com/.well-known/openid-configuration'
-        };
-        break;
- 
-      default:
-        throw new Error(`Unsupported security type: ${security.type}`);
-    }
- 
-    this.securitySchemes.set(schemeName, scheme);
-    return schemeName;
-  }
- 
-  public recordEndpoint(
-    path: string,
-    method: string,
-    request: RequestInfo,
-    response: ResponseInfo
-  ): void {
-    const key = `${method}:${path}`;
-    const endpoint: EndpointInfo = this.endpoints.get(key) || {
-      path,
-      method,
-      responses: {},
-      parameters: [],
-      requestBody: method.toLowerCase() === 'get' ? undefined : {
-        required: false,
-        content: {}
-      }
-    };
- 
-    // Add security schemes if present
-    if (request.security) {
-      endpoint.security = request.security.map(security => {
-        const schemeName = this.addSecurityScheme(security);
-        return { [schemeName]: ['read'] }; // Add default scope
-      });
-    }
- 
-    // Convert path parameters to OpenAPI format
-    const openApiPath = path.replace(/:(\w+)/g, '{$1}');
- 
-    // Add path parameters
-    const pathParams = path.match(/:(\w+)/g) || [];
-    pathParams.forEach(param => {
-      const paramName = param.slice(1);
-      if (!endpoint.parameters.some(p => p.name === paramName)) {
-        endpoint.parameters.push({
-          name: paramName,
-          in: 'path',
-          required: true,
-          schema: {
-            type: 'string',
-            example: paramName // Use the parameter name as an example
-          }
-        });
-      }
-    });
- 
-    // Add query parameters and headers
-    Object.entries(request.query).forEach(([key, value]) => {
-      if (!endpoint.parameters.some(p => p.name === key)) {
-        endpoint.parameters.push({
-          name: key,
-          in: 'query',
-          required: false,
-          schema: {
-            type: 'string',
-            example: value
-          }
-        });
-      }
-    });
- 
-    // Add request headers as parameters
-    if (request.headers) {
-      Object.entries(request.headers).forEach(([name, value]) => {
-        if (!endpoint.parameters.some(p => p.name === name)) {
-          endpoint.parameters.push({
-            name: name,
-            in: 'header',
-            required: false,
-            schema: {
-              type: 'string',
-              example: value
-            }
-          });
-        }
-      });
-    }
- 
-    // Add request body schema if present and not a GET request
-    if (request.body && method.toLowerCase() !== 'get') {
-      const contentType = request.contentType || 'application/json';
-      if (endpoint.requestBody && !endpoint.requestBody.content[contentType]) {
-        const schema = this.generateJsonSchema(request.body);
-        endpoint.requestBody.content[contentType] = {
-          schema
-        };
-      }
-    }
- 
-    // Add response schema
-    const responseContentType = response.contentType || 'application/json';
-    
-    // Initialize response object if it doesn't exist
-    if (!endpoint.responses[response.status]) {
-      endpoint.responses[response.status] = {
-        description: `Response for ${method.toUpperCase()} ${path}`,
-        content: {}
-      };
-    }
- 
-    // Ensure content object exists
-    const responseObj = endpoint.responses[response.status];
-    if (!responseObj.content) {
-      responseObj.content = {};
-    }
- 
-    // Generate schema for the current response
-    const currentSchema = this.generateJsonSchema(response.body);
-    
-    // Get existing schemas for this endpoint and status code
-    const schemaKey = `${key}:${response.status}:${responseContentType}`;
-    const existingSchemas = this.schemaCache.get(schemaKey) || [];
-    
-    // Add the current schema to the cache
-    existingSchemas.push(currentSchema);
-    this.schemaCache.set(schemaKey, existingSchemas);
-    
-    // Merge all schemas for this endpoint and status code
-    const mergedSchema = this.deepMergeSchemas(existingSchemas);
- 
-    // Update the content with the merged schema
-    responseObj.content[responseContentType] = {
-      schema: mergedSchema
-    };
- 
-    // Add response headers
-    if (response.headers && Object.keys(response.headers).length > 0) {
-      endpoint.responses[response.status].headers = Object.entries(response.headers).reduce((acc, [name, value]) => {
-        acc[name] = {
-          schema: {
-            type: 'string',
-            example: value
-          },
-          description: `Response header ${name}`
-        };
-        return acc;
-      }, {} as NonNullable<OpenAPIV3_1.ResponseObject['headers']>);
-    }
- 
-    this.endpoints.set(key, endpoint);
- 
-    // Record in HAR
-    this.recordHAREntry(path, method, request, response);
-  }
- 
-  public getOpenAPISpec(): OpenAPIV3_1.Document {
-    const paths = Array.from(this.endpoints.entries()).reduce<Required<PathsObject>>((acc, [key, info]) => {
-      const [method, path] = key.split(':');
-      
-      if (!acc[path]) {
-        acc[path] = {} as Required<PathItemObject>;
-      }
-      
-      const operation: OpenAPIV3_1.OperationObject = {
-        summary: `${method.toUpperCase()} ${path}`,
-        responses: info.responses,
-      };
- 
-      // Only include parameters if there are any
-      if (info.parameters.length > 0) {
-        operation.parameters = info.parameters;
-      }
- 
-      // Only include requestBody if it exists
-      if (info.requestBody) {
-        operation.requestBody = info.requestBody;
-      }
- 
-      // Add security if it exists
-      if (info.security) {
-        operation.security = info.security;
-      }
- 
-      acc[path][method] = operation;
-      return acc;
-    }, {});
- 
-    const spec: OpenAPIV3_1.Document = {
-      openapi: '3.1.0',
-      info: {
-        title: 'Generated API Documentation',
-        version: '1.0.0',
-        description: 'Automatically generated API documentation from proxy traffic',
-      },
-      servers: [{
-        url: this.targetUrl,
-      }],
-      paths,
-      components: {
-        securitySchemes: Object.fromEntries(this.securitySchemes)
-      }
-    };
- 
-    return spec;
-  }
- 
-  public getOpenAPISpecAsYAML(): string {
-    const spec = this.getOpenAPISpec();
-    return stringify(spec, {
-      indent: 2,
-      simpleKeys: true,
-      strict: true
-    });
-  }
- 
-  public saveOpenAPISpec(outputDir: string): void {
-    const spec = this.getOpenAPISpec();
-    const yamlSpec = this.getOpenAPISpecAsYAML();
- 
-    // Ensure output directory exists
-    if (!fs.existsSync(outputDir)) {
-      fs.mkdirSync(outputDir, { recursive: true });
-    }
- 
-    // Save JSON spec
-    fs.writeFileSync(
-      path.join(outputDir, 'openapi.json'),
-      JSON.stringify(spec, null, 2)
-    );
- 
-    // Save YAML spec
-    fs.writeFileSync(
-      path.join(outputDir, 'openapi.yaml'),
-      yamlSpec
-    );
-  }
- 
-  public generateHAR(): any {
-    return {
-      log: {
-        version: '1.2',
-        creator: {
-          name: 'Arbiter',
-          version: '1.0.0',
-        },
-        entries: this.harEntries,
-      },
-    };
-  }
-}
- 
-export const openApiStore = new OpenAPIStore(); 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/integration/__tests__/proxy.test.ts b/integration/__tests__/proxy.test.ts index ca6f71bd..9a07e77c 100644 --- a/integration/__tests__/proxy.test.ts +++ b/integration/__tests__/proxy.test.ts @@ -82,10 +82,10 @@ describe('Arbiter Integration Tests', () => { targetApi.get('/users/search', (c) => { const limit = c.req.query('limit'); const sort = c.req.query('sort'); - return c.json({ + return c.json({ results: [{ id: 1, name: 'John Doe' }], limit: limit ? parseInt(limit) : 10, - sort: sort || 'asc' + sort: sort || 'asc', }); }); @@ -101,9 +101,9 @@ describe('Arbiter Integration Tests', () => { target: `http://localhost:${targetPort}`, proxyPort: proxyPort, docsPort: docsPort, - verbose: false + verbose: false, }); - + proxyServer = proxy; docsServer = docs; }); @@ -180,7 +180,7 @@ describe('Arbiter Integration Tests', () => { const requestBody = spec.paths?.['/users']?.post?.requestBody as OpenAPIV3_1.RequestBodyObject; expect(requestBody.content?.['application/json']).toBeDefined(); expect(requestBody.content?.['application/json'].schema).toBeDefined(); - + // Validate schema properties based on what we sent in the POST request const schema = requestBody.content?.['application/json'].schema as OpenAPIV3_1.SchemaObject; expect(schema).toBeDefined(); diff --git a/integration/__tests__/server.test.ts b/integration/__tests__/server.test.ts index 0e75455d..e4043ea4 100644 --- a/integration/__tests__/server.test.ts +++ b/integration/__tests__/server.test.ts @@ -17,26 +17,26 @@ import bodyParser from 'body-parser'; describe('Server Integration Tests', () => { const TARGET_PORT = 3000; - const PROXY_PORT = 3005; // Changed to avoid conflicts with other tests - const DOCS_PORT = 3006; // Changed to avoid conflicts with other tests - + const PROXY_PORT = 3005; // Changed to avoid conflicts with other tests + const DOCS_PORT = 3006; // Changed to avoid conflicts with other tests + const TARGET_URL = `http://localhost:${TARGET_PORT}`; const PROXY_URL = `http://localhost:${PROXY_PORT}`; const DOCS_URL = `http://localhost:${DOCS_PORT}`; - + let targetServer: any; let proxyServer: Server; let docsServer: Server; - + beforeAll(async () => { // Create a mock target API server const targetApp = new Hono(); - + // Basic GET endpoint targetApp.get('/api/test', (c) => { return c.json({ message: 'Test successful' }); }); - + // POST endpoint for users targetApp.post('/api/users', async (c) => { try { @@ -48,84 +48,85 @@ describe('Server Integration Tests', () => { return c.json({ error: 'Invalid JSON', message: (e as Error).message }); } }); - + // Start the target server targetServer = serve({ port: TARGET_PORT, fetch: targetApp.fetch }); - + // Clear the OpenAPI store openApiStore.clear(); - + // Start the real proxy and docs servers const servers = await startServers({ target: TARGET_URL, proxyPort: PROXY_PORT, docsPort: DOCS_PORT, - verbose: false + verbose: false, }); - + proxyServer = servers.proxyServer; docsServer = servers.docsServer; }); - + afterAll(async () => { // Shutdown servers targetServer?.close(); proxyServer?.close(); docsServer?.close(); }); - + it('should respond to GET requests and record them', async () => { const response = await fetch(`${PROXY_URL}/api/test`); expect(response.status).toBe(200); const body = await response.json(); expect(body).toEqual({ message: 'Test successful' }); - + // Verify that the endpoint was recorded in OpenAPI spec const specResponse = await fetch(`${DOCS_URL}/openapi.json`); - const spec = await specResponse.json() as OpenAPIV3_1.Document; + const spec = (await specResponse.json()) as OpenAPIV3_1.Document; expect(spec.paths?.['/api/test']?.get).toBeDefined(); - + // Verify that the endpoint was recorded in HAR format const harResponse = await fetch(`${DOCS_URL}/har`); - const har = await harResponse.json() as { log: { entries: any[] } }; + const har = (await harResponse.json()) as { log: { entries: any[] } }; expect(har.log.entries.length).toBeGreaterThan(0); expect(har.log.entries).toContainEqual( expect.objectContaining({ request: expect.objectContaining({ method: 'GET', - url: expect.stringContaining('/api/test') - }) + url: expect.stringContaining('/api/test'), + }), }) ); }); - + it('should handle POST requests with JSON bodies', async () => { const payload = { name: 'Test User', email: 'test@example.com' }; - + const response = await fetch(`${PROXY_URL}/api/users`, { method: 'POST', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - body: JSON.stringify(payload) + body: JSON.stringify(payload), }); - + expect(response.status).toBe(201); const body = await response.json(); expect(body).toEqual({ id: 1, name: 'Test User', email: 'test@example.com' }); - + // Verify that the endpoint and request body were recorded const specResponse = await fetch(`${DOCS_URL}/openapi.json`); - const spec = await specResponse.json() as OpenAPIV3_1.Document; + const spec = (await specResponse.json()) as OpenAPIV3_1.Document; expect(spec.paths?.['/api/users']?.post?.requestBody).toBeDefined(); - + // Check that the request schema was generated if (spec.paths?.['/api/users']?.post?.requestBody) { - const requestBody = spec.paths['/api/users'].post.requestBody as OpenAPIV3_1.RequestBodyObject; + const requestBody = spec.paths['/api/users'].post + .requestBody as OpenAPIV3_1.RequestBodyObject; if (requestBody.content) { expect(requestBody.content['application/json']).toBeDefined(); expect(requestBody.content['application/json'].schema).toBeDefined(); } } }); -}); \ No newline at end of file +}); diff --git a/node_modules/.vite/results.json b/node_modules/.vite/results.json index 9297a23d..6f63ff09 100644 --- a/node_modules/.vite/results.json +++ b/node_modules/.vite/results.json @@ -1 +1 @@ -{"version":"3.0.9","results":[[":src/store/__tests__/openApiStore.test.ts",{"duration":18.337797000000023,"failed":false}],[":src/middleware/__tests__/harRecorder.test.ts",{"duration":17.202578000000017,"failed":false}],[":integration/__tests__/proxy.test.ts",{"duration":71.735096,"failed":false}],[":integration/__tests__/server.test.ts",{"duration":47.88281499999994,"failed":false}],[":src/__tests__/cli.test.ts",{"duration":4.6258020000000215,"failed":false}]]} \ No newline at end of file +{"version":"3.0.9","results":[[":src/store/__tests__/openApiStore.test.ts",{"duration":17.177212999999995,"failed":false}],[":src/middleware/__tests__/harRecorder.test.ts",{"duration":16.706658000000004,"failed":false}],[":integration/__tests__/proxy.test.ts",{"duration":72.56247300000007,"failed":false}],[":integration/__tests__/server.test.ts",{"duration":47.499804999999924,"failed":false}],[":src/__tests__/cli.test.ts",{"duration":4.407485999999949,"failed":false}]]} \ No newline at end of file diff --git a/package.json b/package.json index f6e696ef..e448d8a1 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "dev": "ts-node-dev --respawn --transpile-only src/cli.ts", "cli": "ts-node-dev --respawn --transpile-only src/cli.ts", "test": "vitest run", - "test:coverage": "vitest run --coverage", "test:unit": "vitest src/**/__tests__/*.test.ts", "test:integration": "vitest integration/__tests__/*.test.ts", "test:ci": "vitest run", diff --git a/src/middleware/__tests__/harRecorder.test.ts b/src/middleware/__tests__/harRecorder.test.ts index 6f5bc9ad..3cdcd9eb 100644 --- a/src/middleware/__tests__/harRecorder.test.ts +++ b/src/middleware/__tests__/harRecorder.test.ts @@ -58,7 +58,7 @@ describe('HAR Recorder Middleware', () => { it('should handle POST requests with JSON body', async () => { const requestBody = { name: 'Test User', email: 'test@example.com' }; const jsonBody = JSON.stringify(requestBody); - + const store = new Map(); const ctx = { req: { @@ -99,12 +99,12 @@ describe('HAR Recorder Middleware', () => { expect(har.log.entries).toHaveLength(1); expect(har.log.entries[0].request.method).toBe('POST'); expect(har.log.entries[0].request.url).toBe('http://localhost:8080/users'); - + // Check request body was properly captured const entry = openApiStore.getOpenAPISpec().paths?.['/users']?.post; expect(entry).toBeDefined(); expect(entry?.requestBody).toBeDefined(); - + // Check response body and status expect(har.log.entries[0].response.status).toBe(201); expect(har.log.entries[0].response.content.text).toEqual(expect.stringContaining('Test User')); @@ -113,7 +113,7 @@ describe('HAR Recorder Middleware', () => { it('should handle PUT requests with JSON body', async () => { const requestBody = { name: 'Updated User', email: 'updated@example.com' }; const jsonBody = JSON.stringify(requestBody); - + const store = new Map(); const ctx = { req: { @@ -153,7 +153,7 @@ describe('HAR Recorder Middleware', () => { const har = openApiStore.generateHAR(); expect(har.log.entries).toHaveLength(1); expect(har.log.entries[0].request.method).toBe('PUT'); - + // Check request body was properly captured const entry = openApiStore.getOpenAPISpec().paths?.['/users/{id}']?.put; expect(entry).toBeDefined(); @@ -163,7 +163,7 @@ describe('HAR Recorder Middleware', () => { it('should handle PATCH requests with JSON body', async () => { const requestBody = { name: 'Partially Updated User' }; const jsonBody = JSON.stringify(requestBody); - + const store = new Map(); const ctx = { req: { @@ -188,12 +188,15 @@ describe('HAR Recorder Middleware', () => { } as unknown as Context; const next = async () => { - ctx.res = new Response(JSON.stringify({ id: 1, name: 'Partially Updated User', email: 'existing@example.com' }), { - status: 200, - headers: new Headers({ - 'content-type': 'application/json', - }), - }); + ctx.res = new Response( + JSON.stringify({ id: 1, name: 'Partially Updated User', email: 'existing@example.com' }), + { + status: 200, + headers: new Headers({ + 'content-type': 'application/json', + }), + } + ); }; // Get the middleware function and call it @@ -203,7 +206,7 @@ describe('HAR Recorder Middleware', () => { const har = openApiStore.generateHAR(); expect(har.log.entries).toHaveLength(1); expect(har.log.entries[0].request.method).toBe('PATCH'); - + // Check request body was properly captured const entry = openApiStore.getOpenAPISpec().paths?.['/users/{id}']?.patch; expect(entry).toBeDefined(); @@ -213,9 +216,9 @@ describe('HAR Recorder Middleware', () => { it('should handle form data in requests', async () => { const formData = new Map([ ['username', 'testuser'], - ['email', 'test@example.com'] + ['email', 'test@example.com'], ]); - + const store = new Map(); const ctx = { req: { @@ -254,7 +257,7 @@ describe('HAR Recorder Middleware', () => { const har = openApiStore.generateHAR(); expect(har.log.entries).toHaveLength(1); - + // Check form data was captured const entry = openApiStore.getOpenAPISpec().paths?.['/form']?.post; expect(entry).toBeDefined(); @@ -263,7 +266,7 @@ describe('HAR Recorder Middleware', () => { it('should handle text content in requests', async () => { const textContent = 'This is a plain text content'; - + const store = new Map(); const ctx = { req: { @@ -302,7 +305,7 @@ describe('HAR Recorder Middleware', () => { const har = openApiStore.generateHAR(); expect(har.log.entries).toHaveLength(1); - + // Check text content was captured const entry = openApiStore.getOpenAPISpec().paths?.['/text']?.post; expect(entry).toBeDefined(); @@ -351,20 +354,20 @@ describe('HAR Recorder Middleware', () => { { name: 'foo', value: 'bar' }, { name: 'baz', value: 'qux' }, ]); - + // Check query parameters in OpenAPI spec const parameters = openApiStore.getOpenAPISpec().paths?.['/test']?.get?.parameters; expect(parameters).toBeDefined(); expect(parameters).toContainEqual( expect.objectContaining({ name: 'foo', - in: 'query' + in: 'query', }) ); expect(parameters).toContainEqual( expect.objectContaining({ name: 'baz', - in: 'query' + in: 'query', }) ); }); @@ -374,7 +377,7 @@ describe('HAR Recorder Middleware', () => { const customHeaders: Record = { 'content-type': 'application/json', 'x-custom-header': 'test-value', - 'authorization': 'Bearer test-token', + authorization: 'Bearer test-token', }; const ctx = { @@ -415,19 +418,19 @@ describe('HAR Recorder Middleware', () => { 'get', { query: {}, - headers: { - 'authorization': 'Bearer test-token', - 'x-custom-header': 'test-value' + headers: { + authorization: 'Bearer test-token', + 'x-custom-header': 'test-value', }, contentType: 'application/json', body: null, - security: [{ type: 'http', scheme: 'bearer' }] + security: [{ type: 'http', scheme: 'bearer' }], }, { status: 200, headers: {}, contentType: 'application/json', - body: { success: true } + body: { success: true }, } ); @@ -440,17 +443,17 @@ describe('HAR Recorder Middleware', () => { name: 'x-custom-header', value: 'test-value', }); - + // Check headers in OpenAPI spec const parameters = openApiStore.getOpenAPISpec().paths?.['/test']?.get?.parameters; expect(parameters).toBeDefined(); expect(parameters).toContainEqual( expect.objectContaining({ name: 'x-custom-header', - in: 'header' + in: 'header', }) ); - + // Check security schemes for auth header const spec = openApiStore.getOpenAPISpec(); expect(spec.components?.securitySchemes?.http_).toBeDefined(); @@ -500,11 +503,12 @@ describe('HAR Recorder Middleware', () => { name: 'x-custom-response', value: 'test-value', }); - + // Check response headers in OpenAPI spec - const responseObj = openApiStore.getOpenAPISpec().paths?.['/test']?.get?.responses?.[200] as OpenAPIV3_1.ResponseObject; + const responseObj = openApiStore.getOpenAPISpec().paths?.['/test']?.get + ?.responses?.[200] as OpenAPIV3_1.ResponseObject; expect(responseObj).toBeDefined(); - + // Cast to ResponseObject to access headers property if (responseObj && 'headers' in responseObj && responseObj.headers) { expect(Object.keys(responseObj.headers).length).toBeGreaterThan(0); @@ -550,7 +554,7 @@ describe('HAR Recorder Middleware', () => { const har = openApiStore.generateHAR(); expect(har.log.entries[0].response.status).toBe(500); - + // Check error response in OpenAPI spec const errorResponse = openApiStore.getOpenAPISpec().paths?.['/error']?.get?.responses?.[500]; expect(errorResponse).toBeDefined(); @@ -564,7 +568,9 @@ describe('HAR Recorder Middleware', () => { url: 'http://localhost:8080/test', path: '/test', query: {}, - header: () => { throw new Error('Test error'); }, // Deliberately throw an error + header: () => { + throw new Error('Test error'); + }, // Deliberately throw an error raw: { clone: () => ({ text: async () => '', @@ -589,7 +595,7 @@ describe('HAR Recorder Middleware', () => { // Get the middleware function and call it const middleware = harRecorder(openApiStore); - + // Should not throw await expect(middleware(ctx, next)).resolves.not.toThrow(); }); diff --git a/src/middleware/harRecorder.ts b/src/middleware/harRecorder.ts index b00e5cd2..98f94889 100644 --- a/src/middleware/harRecorder.ts +++ b/src/middleware/harRecorder.ts @@ -11,10 +11,10 @@ export function harRecorder(store: OpenAPIStore): (c: Context, next: Next) => Pr try { // Clone the request body based on content type const contentType = c.req.header('content-type') || ''; - + // Create a copy of the request to avoid consuming the body const reqClone = c.req.raw.clone(); - + if (typeof contentType === 'string' && contentType.includes('application/json')) { const text = await reqClone.text(); try { @@ -22,7 +22,10 @@ export function harRecorder(store: OpenAPIStore): (c: Context, next: Next) => Pr } catch (e) { requestBody = text; // Keep as text if JSON parsing fails } - } else if (typeof contentType === 'string' && contentType.includes('application/x-www-form-urlencoded')) { + } else if ( + typeof contentType === 'string' && + contentType.includes('application/x-www-form-urlencoded') + ) { const formData = await reqClone.formData(); requestBody = Object.fromEntries(formData); } else if (typeof contentType === 'string' && contentType.includes('text/')) { @@ -81,7 +84,7 @@ export function harRecorder(store: OpenAPIStore): (c: Context, next: Next) => Pr // Clone the response to avoid consuming the body const resClone = c.res.clone(); const contentType = c.res.headers.get('content-type') || ''; - + if (typeof contentType === 'string' && contentType.includes('application/json')) { const text = await resClone.text(); try { @@ -96,7 +99,7 @@ export function harRecorder(store: OpenAPIStore): (c: Context, next: Next) => Pr } catch (e) { console.error('Error getting response body:', e); } - + // Record the endpoint store.recordEndpoint( c.req.path, @@ -111,7 +114,7 @@ export function harRecorder(store: OpenAPIStore): (c: Context, next: Next) => Pr status: c.res?.status || 500, headers: responseHeaders, contentType: c.res?.headers.get('content-type') || 'application/json', - body: responseBody // Now using captured response body + body: responseBody, // Now using captured response body } ); } catch (error) { diff --git a/src/server.ts b/src/server.ts index 8f99f6e8..f6974928 100644 --- a/src/server.ts +++ b/src/server.ts @@ -51,14 +51,14 @@ class HARStore { return this.har; } - public addEntry(entry: typeof this.har.log.entries[0]) { + public addEntry(entry: (typeof this.har.log.entries)[0]) { this.har.log.entries.push(entry); } public clear() { this.har.log.entries = []; } - + // Process any entries with raw response buffers private processRawBuffers() { for (const entry of this.har.log.entries) { @@ -66,17 +66,18 @@ class HARStore { try { const buffer = entry._rawResponseBuffer; const contentType = entry.response.content.mimeType; - + // Process buffer based on content-encoding header - const contentEncoding = entry.response.headers.find(h => - h.name.toLowerCase() === 'content-encoding')?.value; - + const contentEncoding = entry.response.headers.find( + (h) => h.name.toLowerCase() === 'content-encoding' + )?.value; + if (contentEncoding) { if (contentEncoding.toLowerCase() === 'gzip') { try { const decompressed = zlib.gunzipSync(buffer); const text = decompressed.toString('utf-8'); - + if (contentType.includes('json')) { try { entry.response.content.text = text; @@ -95,7 +96,7 @@ class HARStore { } else { // For non-compressed responses const text = buffer.toString('utf-8'); - + if (contentType.includes('json')) { try { const json = JSON.parse(text); @@ -110,7 +111,7 @@ class HARStore { } catch (e) { entry.response.content.text = '[Error processing response content]'; } - + // Remove the raw buffer to free memory delete entry._rawResponseBuffer; } @@ -184,7 +185,7 @@ export async function startServers({ res.end(JSON.stringify({ error: 'Proxy error', message: err.message })); } }); - + // Handle proxy response proxyServer.on('proxyReq', (proxyReq, req, res) => { // Store the request body for later use @@ -193,7 +194,7 @@ export async function startServers({ requestBodies.set(requestId, req.body); // Set a custom header to identify the request proxyReq.setHeader('x-request-id', requestId); - + // If the body has been consumed by the body-parser, we need to restream it to the proxy if (req.body) { const bodyData = JSON.stringify(req.body); @@ -211,35 +212,35 @@ export async function startServers({ proxyServer.on('proxyRes', (proxyRes, req, res) => { const startTime = Date.now(); const chunks: Buffer[] = []; - + // Collect response chunks proxyRes.on('data', (chunk: Buffer) => { chunks.push(Buffer.from(chunk)); }); - + // When the response is complete proxyRes.on('end', () => { const endTime = Date.now(); const responseTime = endTime - startTime; - + // Combine response chunks const buffer = Buffer.concat(chunks); - + // Set status code res.statusCode = proxyRes.statusCode || 200; res.statusMessage = proxyRes.statusMessage || ''; - + // Copy ALL headers exactly as they are - Object.keys(proxyRes.headers).forEach(key => { + Object.keys(proxyRes.headers).forEach((key) => { const headerValue = proxyRes.headers[key]; if (headerValue) { res.setHeader(key, headerValue); } }); - + // Send the buffer as the response body without modifying it res.end(buffer); - + // Process HAR and OpenAPI data in the background (next event loop tick) // to avoid delaying the response to the client setImmediate(() => { @@ -247,12 +248,12 @@ export async function startServers({ const method = req.method || 'GET'; const originalUrl = new URL(`http://${req.headers.host}${req.url}`); const path = originalUrl.pathname; - + // Skip web asset requests - don't process JS, CSS, HTML, etc. but keep images and icons if ( - path.endsWith('.js') || - path.endsWith('.css') || - path.endsWith('.html') || + path.endsWith('.js') || + path.endsWith('.css') || + path.endsWith('.html') || path.endsWith('.htm') || path.endsWith('.woff') || path.endsWith('.woff2') || @@ -265,7 +266,7 @@ export async function startServers({ } return; } - + // Skip if contentType is related to web assets, but keep images const contentType = proxyRes.headers['content-type'] || ''; if ( @@ -279,14 +280,14 @@ export async function startServers({ } return; } - + // Extract query parameters const queryParams: Record = {}; const urlSearchParams = new URLSearchParams(originalUrl.search); urlSearchParams.forEach((value, key) => { queryParams[key] = value; }); - + // Extract request headers const requestHeaders: Record = {}; for (const [key, value] of Object.entries(req.headers)) { @@ -296,7 +297,7 @@ export async function startServers({ requestHeaders[key] = value[0]; } } - + // Extract response headers const responseHeaders: Record = {}; for (const [key, value] of Object.entries(proxyRes.headers)) { @@ -306,7 +307,7 @@ export async function startServers({ responseHeaders[key] = value[0]; } } - + // Get request body from our map if available let requestBody = undefined; if (['POST', 'PUT', 'PATCH'].includes(method)) { @@ -320,10 +321,10 @@ export async function startServers({ requestBody = req.body; } } - + // Store minimal data for HAR entry - delay expensive processing const requestUrl = `${target}${path}${originalUrl.search}`; - + // Create lighter HAR entry with minimal processing const harEntry = { startedDateTime: new Date(startTime).toISOString(), @@ -335,30 +336,41 @@ export async function startServers({ headers: Object.entries(requestHeaders) .filter(([key]) => key.toLowerCase() !== 'content-length') .map(([name, value]) => ({ name, value })), - queryString: Object.entries(queryParams).map(([name, value]) => ({ name, value })), - postData: requestBody ? { - mimeType: requestHeaders['content-type'] || 'application/json', - text: typeof requestBody === 'string' ? requestBody : JSON.stringify(requestBody) - } : undefined, + queryString: Object.entries(queryParams).map(([name, value]) => ({ + name, + value, + })), + postData: requestBody + ? { + mimeType: requestHeaders['content-type'] || 'application/json', + text: + typeof requestBody === 'string' + ? requestBody + : JSON.stringify(requestBody), + } + : undefined, }, response: { status: proxyRes.statusCode || 200, statusText: proxyRes.statusCode === 200 ? 'OK' : 'Error', httpVersion: 'HTTP/1.1', - headers: Object.entries(responseHeaders).map(([name, value]) => ({ name, value })), + headers: Object.entries(responseHeaders).map(([name, value]) => ({ + name, + value, + })), content: { size: buffer.length, mimeType: responseHeaders['content-type'] || 'application/octet-stream', // Store raw buffer and defer text conversion/parsing until needed - text: '[Response content stored]' + text: '[Response content stored]', }, }, _rawResponseBuffer: buffer, // Store for later processing if needed }; - + // Add the HAR entry to the store harStore.addEntry(harEntry); - + // Extract security schemes from headers - minimal work const securitySchemes: SecurityInfo[] = []; if (requestHeaders['x-api-key']) { @@ -380,7 +392,7 @@ export async function startServers({ scheme: 'basic' as const, }); } - + // Store minimal data in OpenAPI store - just record the endpoint and method // This defers schema generation until actually requested openApiStore.recordEndpoint( @@ -402,39 +414,39 @@ export async function startServers({ rawData: buffer, } ); - + if (verbose) { console.log(`${method} ${path} -> ${proxyRes.statusCode}`); } }); // End of setImmediate }); }); - } - ] + }, + ], }); proxyApp.use('/', proxyMiddleware); - + // Create docs app with Express const docsApp = express(); docsApp.use(cors()); - + // Create documentation endpoints docsApp.get('/har', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(harStore.getHAR())); }); - + docsApp.get('/openapi.json', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(openApiStore.getOpenAPISpec())); }); - + docsApp.get('/openapi.yaml', (req, res) => { res.setHeader('Content-Type', 'text/plain'); res.send(openApiStore.getOpenAPISpecAsYAML()); }); - + docsApp.get('/docs', (req, res) => { res.setHeader('Content-Type', 'text/html'); res.send(` @@ -452,7 +464,7 @@ export async function startServers({ `); }); - + // Home page with links docsApp.get('/', (req, res) => { res.setHeader('Content-Type', 'text/html'); @@ -482,7 +494,7 @@ export async function startServers({ `); }); - + // Function to check if a port is available async function isPortAvailable(port: number): Promise { return new Promise((resolve) => { @@ -497,7 +509,7 @@ export async function startServers({ .listen(port); }); } - + // Function to find an available port async function findAvailablePort(startPort: number): Promise { let port = startPort; @@ -506,11 +518,11 @@ export async function startServers({ } return port; } - + // Start servers const availableProxyPort = await findAvailablePort(proxyPort); const availableDocsPort = await findAvailablePort(docsPort); - + if (availableProxyPort !== proxyPort) { console.log( chalk.yellow(`Port ${proxyPort} is in use, using port ${availableProxyPort} instead`) @@ -521,11 +533,11 @@ export async function startServers({ chalk.yellow(`Port ${docsPort} is in use, using port ${availableDocsPort} instead`) ); } - + // Create HTTP servers const proxyServer = createServer(proxyApp); const docsServer = createServer(docsApp); - + // Start servers return new Promise((resolve, reject) => { try { @@ -539,10 +551,14 @@ export async function startServers({ console.log(chalk.cyan(` API Reference: http://localhost:${availableDocsPort}/docs`)); console.log('\n' + chalk.bold('Exports:')); console.log(chalk.cyan(` HAR Export: http://localhost:${availableDocsPort}/har`)); - console.log(chalk.cyan(` OpenAPI JSON: http://localhost:${availableDocsPort}/openapi.json`)); - console.log(chalk.cyan(` OpenAPI YAML: http://localhost:${availableDocsPort}/openapi.yaml`)); + console.log( + chalk.cyan(` OpenAPI JSON: http://localhost:${availableDocsPort}/openapi.json`) + ); + console.log( + chalk.cyan(` OpenAPI YAML: http://localhost:${availableDocsPort}/openapi.yaml`) + ); console.log('\n' + chalk.yellow('Press Ctrl+C to stop')); - + resolve({ proxyServer, docsServer }); }); }); @@ -550,7 +566,7 @@ export async function startServers({ reject(error); } }); - + // Handle graceful shutdown const shutdown = (signal: string): void => { console.info(`Received ${signal}, shutting down...`); @@ -558,11 +574,11 @@ export async function startServers({ docsServer.close(); process.exit(0); }; - + process.on('SIGTERM', () => { shutdown('SIGTERM'); }); - + process.on('SIGINT', () => { shutdown('SIGINT'); }); diff --git a/src/store/__tests__/openApiStore.test.ts b/src/store/__tests__/openApiStore.test.ts index 9b9b53b3..edf68c8d 100644 --- a/src/store/__tests__/openApiStore.test.ts +++ b/src/store/__tests__/openApiStore.test.ts @@ -577,7 +577,7 @@ describe('OpenAPI Store', () => { describe('Basic functionality', () => { it('should initialize with correct default values', () => { const spec = openApiStore.getOpenAPISpec(); - + expect(spec.openapi).toBe('3.1.0'); expect(spec.info.title).toBe('API Documentation'); expect(spec.info.version).toBe('1.0.0'); @@ -588,7 +588,7 @@ describe('OpenAPI Store', () => { it('should set target URL correctly', () => { openApiStore.setTargetUrl('https://example.com/api'); const spec = openApiStore.getOpenAPISpec(); - + expect(spec.servers?.[0]?.url).toBe('https://example.com/api'); }); @@ -600,11 +600,11 @@ describe('OpenAPI Store', () => { { query: {}, headers: {}, contentType: 'application/json', body: null }, { status: 200, headers: {}, contentType: 'application/json', body: { success: true } } ); - + // Verify it was added const spec1 = openApiStore.getOpenAPISpec(); expect(Object.keys(spec1.paths || {})).toHaveLength(1); - + // Clear and verify it's gone openApiStore.clear(); const spec2 = openApiStore.getOpenAPISpec(); @@ -617,79 +617,84 @@ describe('OpenAPI Store', () => { openApiStore.recordEndpoint( '/users', 'get', - { - query: { limit: '10', offset: '0' }, - headers: { 'accept': 'application/json' }, - contentType: 'application/json', - body: null + { + query: { limit: '10', offset: '0' }, + headers: { accept: 'application/json' }, + contentType: 'application/json', + body: null, }, - { - status: 200, - headers: { 'content-type': 'application/json' }, - contentType: 'application/json', - body: [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }] + { + status: 200, + headers: { 'content-type': 'application/json' }, + contentType: 'application/json', + body: [ + { id: 1, name: 'John Doe' }, + { id: 2, name: 'Jane Smith' }, + ], } ); - + const spec = openApiStore.getOpenAPISpec(); - + // Check path exists expect(spec.paths?.['/users']).toBeDefined(); expect(spec.paths?.['/users']?.get).toBeDefined(); - + // Check query parameters const params = spec.paths?.['/users']?.get?.parameters; expect(params).toBeDefined(); expect(params).toContainEqual( expect.objectContaining({ name: 'limit', - in: 'query' + in: 'query', }) ); expect(params).toContainEqual( expect.objectContaining({ name: 'offset', - in: 'query' + in: 'query', }) ); - + // Check response expect(spec.paths?.['/users']?.get?.responses?.[200]).toBeDefined(); - const content = (spec.paths?.['/users']?.get?.responses?.[200] as OpenAPIV3_1.ResponseObject)?.content; + const content = (spec.paths?.['/users']?.get?.responses?.[200] as OpenAPIV3_1.ResponseObject) + ?.content; expect(content?.['application/json']).toBeDefined(); }); it('should record a POST endpoint with request body', () => { const requestBody = { name: 'Test User', email: 'test@example.com' }; - + openApiStore.recordEndpoint( '/users', 'post', - { - query: {}, - headers: { 'content-type': 'application/json' }, - contentType: 'application/json', - body: requestBody + { + query: {}, + headers: { 'content-type': 'application/json' }, + contentType: 'application/json', + body: requestBody, }, - { - status: 201, - headers: { 'content-type': 'application/json' }, - contentType: 'application/json', - body: { id: 1, ...requestBody } + { + status: 201, + headers: { 'content-type': 'application/json' }, + contentType: 'application/json', + body: { id: 1, ...requestBody }, } ); - + const spec = openApiStore.getOpenAPISpec(); - + // Check path exists expect(spec.paths?.['/users']).toBeDefined(); expect(spec.paths?.['/users']?.post).toBeDefined(); - + // Check request body expect(spec.paths?.['/users']?.post?.requestBody).toBeDefined(); - const content = (spec.paths?.['/users']?.post?.requestBody as OpenAPIV3_1.RequestBodyObject)?.content; + const content = (spec.paths?.['/users']?.post?.requestBody as OpenAPIV3_1.RequestBodyObject) + ?.content; expect(content?.['application/json']).toBeDefined(); - + // Check response expect(spec.paths?.['/users']?.post?.responses?.[201]).toBeDefined(); }); @@ -699,28 +704,44 @@ describe('OpenAPI Store', () => { '/users/123', 'get', { query: {}, headers: {}, contentType: 'application/json', body: null }, - { status: 200, headers: {}, contentType: 'application/json', body: { id: 123, name: 'John Doe' } } + { + status: 200, + headers: {}, + contentType: 'application/json', + body: { id: 123, name: 'John Doe' }, + } ); - + // Now record another endpoint with a different ID to help OpenAPI identify the path parameter openApiStore.recordEndpoint( '/users/456', 'get', { query: {}, headers: {}, contentType: 'application/json', body: null }, - { status: 200, headers: {}, contentType: 'application/json', body: { id: 456, name: 'Jane Smith' } } + { + status: 200, + headers: {}, + contentType: 'application/json', + body: { id: 456, name: 'Jane Smith' }, + } ); - + const spec = openApiStore.getOpenAPISpec(); - + // Check that the path was correctly parameterized expect(spec.paths?.['/users/{id}']).toBeDefined(); if (spec.paths?.['/users/{id}']) { expect(spec.paths['/users/{id}'].get).toBeDefined(); - + // Check that the path parameter is defined const params = spec.paths['/users/{id}'].get?.parameters; expect(params).toBeDefined(); - expect(params?.some(p => (p as OpenAPIV3_1.ParameterObject).name === 'id' && (p as OpenAPIV3_1.ParameterObject).in === 'path')).toBe(true); + expect( + params?.some( + (p) => + (p as OpenAPIV3_1.ParameterObject).name === 'id' && + (p as OpenAPIV3_1.ParameterObject).in === 'path' + ) + ).toBe(true); } }); @@ -729,48 +750,60 @@ describe('OpenAPI Store', () => { openApiStore.recordEndpoint( '/secure', 'get', - { - query: {}, - headers: { 'x-api-key': 'test-key' }, - contentType: 'application/json', + { + query: {}, + headers: { 'x-api-key': 'test-key' }, + contentType: 'application/json', body: null, - security: [{ type: 'apiKey', name: 'x-api-key', in: 'header' }] + security: [{ type: 'apiKey', name: 'x-api-key', in: 'header' }], }, - { status: 200, headers: {}, contentType: 'application/json', body: { message: 'Secret data' } } + { + status: 200, + headers: {}, + contentType: 'application/json', + body: { message: 'Secret data' }, + } ); - + // Record an endpoint with Bearer token openApiStore.recordEndpoint( '/auth/profile', 'get', - { - query: {}, - headers: { 'authorization': 'Bearer token123' }, - contentType: 'application/json', + { + query: {}, + headers: { authorization: 'Bearer token123' }, + contentType: 'application/json', body: null, - security: [{ type: 'http', scheme: 'bearer' }] + security: [{ type: 'http', scheme: 'bearer' }], }, - { status: 200, headers: {}, contentType: 'application/json', body: { id: 1, username: 'admin' } } + { + status: 200, + headers: {}, + contentType: 'application/json', + body: { id: 1, username: 'admin' }, + } ); - + const spec = openApiStore.getOpenAPISpec(); - + // Check security schemes are defined expect(spec.components?.securitySchemes).toBeDefined(); - + // Check API Key security scheme - const apiKeyScheme = spec.components?.securitySchemes?.apiKey_ as OpenAPIV3_1.ApiKeySecurityScheme; + const apiKeyScheme = spec.components?.securitySchemes + ?.apiKey_ as OpenAPIV3_1.ApiKeySecurityScheme; expect(apiKeyScheme).toBeDefined(); expect(apiKeyScheme.type).toBe('apiKey'); expect(apiKeyScheme.in).toBe('header'); expect(apiKeyScheme.name).toBe('x-api-key'); - + // Check Bearer token security scheme - const bearerScheme = spec.components?.securitySchemes?.http_ as OpenAPIV3_1.HttpSecurityScheme; + const bearerScheme = spec.components?.securitySchemes + ?.http_ as OpenAPIV3_1.HttpSecurityScheme; expect(bearerScheme).toBeDefined(); expect(bearerScheme.type).toBe('http'); expect(bearerScheme.scheme).toBe('bearer'); - + // Check security requirements on endpoints expect(spec.paths?.['/secure']?.get?.security).toBeDefined(); expect(spec.paths?.['/auth/profile']?.get?.security).toBeDefined(); @@ -782,7 +815,7 @@ describe('OpenAPI Store', () => { const data = { id: 1, name: 'John Doe', active: true, age: 30 }; // @ts-ignore: Testing private method const schema = openApiStore.generateJsonSchema(data); - + expect(schema.type).toBe('object'); expect((schema.properties?.id as OpenAPIV3_1.SchemaObject).type).toBe('integer'); expect((schema.properties?.name as OpenAPIV3_1.SchemaObject).type).toBe('string'); @@ -793,11 +826,11 @@ describe('OpenAPI Store', () => { it('should generate schema from array', () => { const data = [ { id: 1, name: 'John Doe' }, - { id: 2, name: 'Jane Smith' } + { id: 2, name: 'Jane Smith' }, ]; // @ts-ignore: Testing private method const schema = openApiStore.generateJsonSchema(data); - + expect(schema.type).toBe('array'); // Using ts-ignore since we're accessing a property that might not exist on all schema types // @ts-ignore @@ -817,16 +850,21 @@ describe('OpenAPI Store', () => { address: { street: '123 Main St', city: 'Anytown', - zipCode: '12345' + zipCode: '12345', }, - tags: ['developer', 'javascript'] + tags: ['developer', 'javascript'], }; // @ts-ignore: Testing private method const schema = openApiStore.generateJsonSchema(data); - + expect(schema.type).toBe('object'); expect((schema.properties?.address as OpenAPIV3_1.SchemaObject).type).toBe('object'); - expect(((schema.properties?.address as OpenAPIV3_1.SchemaObject).properties?.street as OpenAPIV3_1.SchemaObject).type).toBe('string'); + expect( + ( + (schema.properties?.address as OpenAPIV3_1.SchemaObject).properties + ?.street as OpenAPIV3_1.SchemaObject + ).type + ).toBe('string'); expect((schema.properties?.tags as OpenAPIV3_1.SchemaObject).type).toBe('array'); // @ts-ignore expect((schema.properties?.tags as OpenAPIV3_1.SchemaObject).items?.type).toBe('string'); @@ -836,20 +874,20 @@ describe('OpenAPI Store', () => { const data = { id: 1, name: 'John Doe', description: null }; // @ts-ignore: Testing private method const schema = openApiStore.generateJsonSchema(data); - + expect((schema.properties?.description as OpenAPIV3_1.SchemaObject).type).toBe('null'); }); it('should detect proper types for numeric values', () => { - const data = { + const data = { integer: 42, float: 3.14, scientific: 1e6, - zero: 0 + zero: 0, }; // @ts-ignore: Testing private method const schema = openApiStore.generateJsonSchema(data); - + expect((schema.properties?.integer as OpenAPIV3_1.SchemaObject).type).toBe('integer'); expect((schema.properties?.float as OpenAPIV3_1.SchemaObject).type).toBe('number'); expect((schema.properties?.scientific as OpenAPIV3_1.SchemaObject).type).toBe('integer'); @@ -861,7 +899,7 @@ describe('OpenAPI Store', () => { it('should detect and generate schema for array-like structures', () => { // @ts-ignore: Testing private method const schema = openApiStore.generateSchemaFromStructure('[{"id":1,"name":"test"},{"id":2}]'); - + expect(schema.type).toBe('array'); // TypeScript doesn't recognize that an array schema will have items // @ts-ignore @@ -870,8 +908,10 @@ describe('OpenAPI Store', () => { it('should detect and generate schema for object-like structures', () => { // @ts-ignore: Testing private method - const schema = openApiStore.generateSchemaFromStructure('{"id":1,"name":"test","active":true}'); - + const schema = openApiStore.generateSchemaFromStructure( + '{"id":1,"name":"test","active":true}' + ); + expect(schema.type).toBe('object'); expect(schema.properties).toBeDefined(); expect(schema.properties?.id).toBeDefined(); @@ -882,7 +922,7 @@ describe('OpenAPI Store', () => { it('should handle unstructured content', () => { // @ts-ignore: Testing private method const schema = openApiStore.generateSchemaFromStructure('This is just plain text'); - + expect(schema.type).toBe('string'); }); }); @@ -896,15 +936,15 @@ describe('OpenAPI Store', () => { { query: {}, headers: {}, contentType: 'application/json', body: null }, { status: 200, headers: {}, contentType: 'application/json', body: { success: true } } ); - + const har = openApiStore.generateHAR(); - + expect(har.log).toBeDefined(); expect(har.log.version).toBe('1.2'); expect(har.log.creator).toBeDefined(); expect(har.log.entries).toBeDefined(); expect(har.log.entries).toHaveLength(1); - + const entry = har.log.entries[0]; expect(entry.request.method).toBe('GET'); expect(entry.request.url).toBe('http://localhost:8080/test'); @@ -921,9 +961,9 @@ describe('OpenAPI Store', () => { { query: {}, headers: {}, contentType: 'application/json', body: null }, { status: 200, headers: {}, contentType: 'application/json', body: { success: true } } ); - + const yaml = openApiStore.getOpenAPISpecAsYAML(); - + expect(yaml).toContain('openapi: 3.1.0'); expect(yaml).toContain('paths:'); expect(yaml).toContain('/test:'); diff --git a/src/store/openApiStore.ts b/src/store/openApiStore.ts index d66e5f8e..16344ffa 100644 --- a/src/store/openApiStore.ts +++ b/src/store/openApiStore.ts @@ -194,12 +194,14 @@ export class OpenAPIStore { if (obj.length === 0) return { type: 'array', items: { type: 'object' } }; // Check if all items are objects with similar structure - const allObjects = obj.every(item => typeof item === 'object' && item !== null && !Array.isArray(item)); - + const allObjects = obj.every( + (item) => typeof item === 'object' && item !== null && !Array.isArray(item) + ); + if (allObjects) { // Generate a schema for the first object const firstObjectSchema = this.generateJsonSchema(obj[0]); - + // Use that as a template for all items return { type: 'array', @@ -209,32 +211,35 @@ export class OpenAPIStore { } // Check if all items are primitives of the same type - if (obj.length > 0 && - obj.every(item => typeof item === 'string' || - typeof item === 'number' || - typeof item === 'boolean')) { + if ( + obj.length > 0 && + obj.every( + (item) => + typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean' + ) + ) { // Handle arrays of primitives const firstItemType = typeof obj[0]; - if (obj.every(item => typeof item === firstItemType)) { + if (obj.every((item) => typeof item === firstItemType)) { // For numbers, check if they're all integers if (firstItemType === 'number') { const isAllIntegers = obj.every(Number.isInteger); return { type: 'array', items: { - type: isAllIntegers ? 'integer' : 'number' + type: isAllIntegers ? 'integer' : 'number', }, - example: obj + example: obj, }; } - + // For strings and booleans return { type: 'array', items: { - type: firstItemType as OpenAPIV3_1.NonArraySchemaObjectType + type: firstItemType as OpenAPIV3_1.NonArraySchemaObjectType, }, - example: obj + example: obj, }; } } @@ -335,10 +340,12 @@ export class OpenAPIStore { value: String(value), // Ensure value is a string })), // Ensure postData is properly included for all requests with body - postData: request.body ? { - mimeType: request.contentType, - text: typeof request.body === 'string' ? request.body : JSON.stringify(request.body), - } : undefined, + postData: request.body + ? { + mimeType: request.contentType, + text: typeof request.body === 'string' ? request.body : JSON.stringify(request.body), + } + : undefined, }, response: { status: response.status, @@ -350,12 +357,18 @@ export class OpenAPIStore { })), content: { // If rawData is available, just store size but defer content processing - size: response.rawData ? response.rawData.length : - response.body ? JSON.stringify(response.body).length : 0, + size: response.rawData + ? response.rawData.length + : response.body + ? JSON.stringify(response.body).length + : 0, mimeType: response.contentType || 'application/json', // Use a placeholder for rawData, or convert body as before - text: response.rawData ? '[Content stored but not processed for performance]' : - typeof response.body === 'string' ? response.body : JSON.stringify(response.body), + text: response.rawData + ? '[Content stored but not processed for performance]' + : typeof response.body === 'string' + ? response.body + : JSON.stringify(response.body), }, }, }; @@ -556,17 +569,17 @@ export class OpenAPIStore { responseObj.content[responseContentType] = { schema: { type: 'object', - description: 'Schema generation deferred to improve performance' + description: 'Schema generation deferred to improve performance', }, }; - + // Store the raw data for later processing let pathMap = this.rawDataCache.get(path); if (!pathMap) { pathMap = new Map(); this.rawDataCache.set(path, pathMap); } - + pathMap.set(method, { rawData: response.rawData ? response.rawData.toString('base64') : '', status: response.status, @@ -602,7 +615,7 @@ export class OpenAPIStore { // For each HAR entry with placeholder text, process the raw data for (let i = 0; i < this.harEntries.length; i++) { const entry = this.harEntries[i]; - + // Check if this entry has deferred processing if (entry.response.content.text === '[Content stored but not processed for performance]') { try { @@ -610,21 +623,22 @@ export class OpenAPIStore { const url = new URL(entry.request.url); const path = url.pathname; const method = entry.request.method.toLowerCase(); - + // Try to get the raw data from our cache const pathMap = this.rawDataCache.get(path); if (!pathMap) continue; - + const responseData = pathMap.get(method); if (!responseData || !responseData.rawData) continue; - + // Get content type and encoding info - const contentEncoding = entry.response.headers.find(h => - h.name.toLowerCase() === 'content-encoding')?.value; - + const contentEncoding = entry.response.headers.find( + (h) => h.name.toLowerCase() === 'content-encoding' + )?.value; + // Process based on content type and encoding let text: string; - + // Handle compressed content if (contentEncoding && contentEncoding.includes('gzip')) { const buffer = Buffer.from(responseData.rawData, 'base64'); @@ -635,7 +649,7 @@ export class OpenAPIStore { const buffer = Buffer.from(responseData.rawData, 'base64'); text = buffer.toString('utf-8'); } - + // Process based on content type const contentType = entry.response.content.mimeType; if (contentType.includes('json')) { @@ -686,7 +700,7 @@ export class OpenAPIStore { } if (!operation.responses[responseKey]) { operation.responses[responseKey] = { - description: `Response for status code ${responseKey}` + description: `Response for status code ${responseKey}`, }; } @@ -697,21 +711,23 @@ export class OpenAPIStore { // Determine content type from headers let contentType = 'application/json'; // Default - const contentTypeHeader = Object.keys(headers) - .find(key => key.toLowerCase() === 'content-type'); + const contentTypeHeader = Object.keys(headers).find( + (key) => key.toLowerCase() === 'content-type' + ); if (contentTypeHeader && headers[contentTypeHeader]) { contentType = headers[contentTypeHeader].split(';')[0]; } // Check if content is compressed - const contentEncodingHeader = Object.keys(headers) - .find(key => key.toLowerCase() === 'content-encoding'); + const contentEncodingHeader = Object.keys(headers).find( + (key) => key.toLowerCase() === 'content-encoding' + ); const contentEncoding = contentEncodingHeader ? headers[contentEncodingHeader] : null; // Process based on encoding and content type try { let text: string; - + // Handle compressed content if (contentEncoding && contentEncoding.includes('gzip')) { const buffer = Buffer.from(rawData, 'base64'); @@ -729,10 +745,10 @@ export class OpenAPIStore { try { // First attempt standard JSON parsing const jsonData = JSON.parse(text); - + const schema = this.generateJsonSchema(jsonData); response.content[contentType] = { - schema + schema, }; } catch (e) { // Try cleaning the JSON first @@ -740,10 +756,10 @@ export class OpenAPIStore { // Clean the JSON string const cleanedText = this.cleanJsonString(text); const jsonData = JSON.parse(cleanedText); - + const schema = this.generateJsonSchema(jsonData); response.content[contentType] = { - schema + schema, }; } catch (e2) { // If parsing still fails, try to infer the schema from structure @@ -751,15 +767,15 @@ export class OpenAPIStore { // Looks like JSON-like structure, infer schema const schema = this.generateSchemaFromStructure(text); response.content[contentType] = { - schema + schema, }; } else { // Not JSON-like, treat as string response.content[contentType] = { schema: { type: 'string', - description: 'Non-parseable content' - } + description: 'Non-parseable content', + }, }; } } @@ -770,8 +786,8 @@ export class OpenAPIStore { schema: { type: 'string', format: 'xml', - description: 'XML content' - } + description: 'XML content', + }, }; } else if (contentType.includes('image/')) { // Handle image content @@ -779,18 +795,16 @@ export class OpenAPIStore { schema: { type: 'string', format: 'binary', - description: 'Image content' - } + description: 'Image content', + }, }; } else { // Handle other content types response.content[contentType] = { schema: { type: 'string', - description: text.length > 100 ? - `${text.substring(0, 100)}...` : - text - } + description: text.length > 100 ? `${text.substring(0, 100)}...` : text, + }, }; } } catch (error) { @@ -799,8 +813,8 @@ export class OpenAPIStore { response.content['text/plain'] = { schema: { type: 'string', - description: 'Error processing content' - } + description: 'Error processing content', + }, }; } } @@ -813,7 +827,7 @@ export class OpenAPIStore { public getOpenAPISpec(): OpenAPIV3_1.Document { // Process any deferred raw data before generating the spec this.processRawData(); - + const paths = Array.from(this.endpoints.entries()).reduce>( (acc, [key, info]) => { const [method, path] = key.split(':'); @@ -939,7 +953,7 @@ export class OpenAPIStore { public generateHAR(): any { // Process any raw data before generating HAR this.processHAREntries(); - + return { log: { version: '1.2', @@ -956,7 +970,7 @@ export class OpenAPIStore { private generateSchemaFromStructure(text: string): OpenAPIV3_1.SchemaObject { // First, try to determine if this is an array or object const trimmedText = text.trim(); - + if (trimmedText.startsWith('[') && trimmedText.endsWith(']')) { // Looks like an array return { @@ -964,37 +978,37 @@ export class OpenAPIStore { description: 'Array-like structure detected', items: { type: 'object', - description: 'Array items (structure inferred)' - } + description: 'Array items (structure inferred)', + }, }; } - + if (trimmedText.startsWith('{') && trimmedText.endsWith('}')) { // Looks like an object - try to extract some field names try { // Extract property names using a regex that looks for different "key": patterns // This matcher is more flexible and can handle single quotes, double quotes, and unquoted keys const propMatches = trimmedText.match(/["']?([a-zA-Z0-9_$]+)["']?\s*:/g) || []; - + if (propMatches.length > 0) { const properties: Record = {}; - + // Extract property names and create a basic schema - propMatches.forEach(match => { + propMatches.forEach((match) => { // Clean up the property name by removing quotes and colon const propName = match.replace(/["']/g, '').replace(':', '').trim(); if (propName && !properties[propName]) { // Try to guess the type based on what follows the property const propPattern = new RegExp(`["']?${propName}["']?\\s*:\\s*(.{1,50})`, 'g'); const valueMatch = propPattern.exec(trimmedText); - + if (valueMatch && valueMatch[1]) { const valueStart = valueMatch[1].trim(); - + if (valueStart.startsWith('{')) { properties[propName] = { type: 'object', - description: 'Nested object detected' + description: 'Nested object detected', }; } else if (valueStart.startsWith('[')) { properties[propName] = { @@ -1002,8 +1016,8 @@ export class OpenAPIStore { description: 'Array value detected', items: { type: 'object', - description: 'Array items (structure inferred)' - } + description: 'Array items (structure inferred)', + }, }; } else if (valueStart.startsWith('"') || valueStart.startsWith("'")) { properties[propName] = { @@ -1024,39 +1038,39 @@ export class OpenAPIStore { } else { properties[propName] = { type: 'string', - description: 'Property detected by structure analysis' + description: 'Property detected by structure analysis', }; } } else { properties[propName] = { type: 'string', - description: 'Property detected by structure analysis' + description: 'Property detected by structure analysis', }; } } }); - + return { type: 'object', properties, - description: 'Object structure detected with properties' + description: 'Object structure detected with properties', }; } } catch (e) { // If property extraction fails, fall back to a generic object schema } - + // Generic object return { type: 'object', - description: 'Object-like structure detected' + description: 'Object-like structure detected', }; } - + // Not clearly structured as JSON return { type: 'string', - description: 'Unstructured content' + description: 'Unstructured content', }; } @@ -1067,31 +1081,29 @@ export class OpenAPIStore { let cleaned = text .replace(/\/\/.*$/gm, '') // Remove single line comments .replace(/\/\*[\s\S]*?\*\//g, ''); // Remove multi-line comments - + // Handle trailing commas in objects and arrays - cleaned = cleaned - .replace(/,\s*}/g, '}') - .replace(/,\s*\]/g, ']'); - + cleaned = cleaned.replace(/,\s*}/g, '}').replace(/,\s*\]/g, ']'); + // Fix unquoted property names (only basic cases) cleaned = cleaned.replace(/([{,]\s*)([a-zA-Z0-9_$]+)(\s*:)/g, '$1"$2"$3'); - + // Fix single quotes used for strings (convert to double quotes) // This is complex - we need to avoid replacing quotes inside quotes let inString = false; let inSingleQuotedString = false; let result = ''; - + for (let i = 0; i < cleaned.length; i++) { const char = cleaned[i]; - const prevChar = i > 0 ? cleaned[i-1] : ''; - + const prevChar = i > 0 ? cleaned[i - 1] : ''; + // Handle escape sequences if (prevChar === '\\') { result += char; continue; } - + if (char === '"' && !inSingleQuotedString) { inString = !inString; result += char; @@ -1102,7 +1114,7 @@ export class OpenAPIStore { result += char; } } - + return result; } catch (e) { // If cleaning fails, return the original text