api-tests-coverage 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard/dist/assets/_basePickBy-CeCjvJWr.js +1 -0
- package/dist/dashboard/dist/assets/_baseUniq-DQMeOG5y.js +1 -0
- package/dist/dashboard/dist/assets/arc-BDIdECDJ.js +1 -0
- package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-D2t8Py1B.js +36 -0
- package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-7B2h6RPh.js +122 -0
- package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-BJS73w81.js +10 -0
- package/dist/dashboard/dist/assets/channel-B5FEo6x8.js +1 -0
- package/dist/dashboard/dist/assets/chunk-4BX2VUAB-rMDV_g4i.js +1 -0
- package/dist/dashboard/dist/assets/chunk-55IACEB6-H2T0HHMf.js +1 -0
- package/dist/dashboard/dist/assets/chunk-B4BG7PRW-BIav900j.js +165 -0
- package/dist/dashboard/dist/assets/chunk-DI55MBZ5-CL1ZxZeg.js +220 -0
- package/dist/dashboard/dist/assets/chunk-FMBD7UC4-BH1h7N7Y.js +15 -0
- package/dist/dashboard/dist/assets/chunk-QN33PNHL-Dzk5VCZ3.js +1 -0
- package/dist/dashboard/dist/assets/chunk-QZHKN3VN-Z3uL3Vu6.js +1 -0
- package/dist/dashboard/dist/assets/chunk-TZMSLE5B-Bk8ko3-5.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-M4p4DdHs.js +1 -0
- package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-M4p4DdHs.js +1 -0
- package/dist/dashboard/dist/assets/clone-DISkn1y_.js +1 -0
- package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-BbDNIhrI.js +1 -0
- package/dist/dashboard/dist/assets/dagre-6UL2VRFP-Niwmlwr0.js +4 -0
- package/dist/dashboard/dist/assets/diagram-PSM6KHXK-D6YSgDDJ.js +24 -0
- package/dist/dashboard/dist/assets/diagram-QEK2KX5R-BIV3o3EV.js +43 -0
- package/dist/dashboard/dist/assets/diagram-S2PKOQOG-B_V6T3Do.js +24 -0
- package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-Dv8XSfJj.js +60 -0
- package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-DHVxWNFx.js +162 -0
- package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-C0zKIcDh.js +267 -0
- package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DbNQAtGz.js +65 -0
- package/dist/dashboard/dist/assets/graph-BUXAK8S4.js +1 -0
- package/dist/dashboard/dist/assets/index-HrRX8fCW.css +1 -0
- package/dist/dashboard/dist/assets/index-k7QMCdxo.js +522 -0
- package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-CbvfFEOs.js +2 -0
- package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-CHncp1wO.js +139 -0
- package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-Ct5tvLkE.js +89 -0
- package/dist/dashboard/dist/assets/layout-DEw3EHVd.js +1 -0
- package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-CM92aa9b.js +68 -0
- package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-Dow8SBXC.js +30 -0
- package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-CHDOoeNa.js +7 -0
- package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-BdQwEiam.js +64 -0
- package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-C2tgBc3h.js +10 -0
- package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-BJapitlJ.js +145 -0
- package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-CAMqhH5J.js +1 -0
- package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-DMcei2iB.js +1 -0
- package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-CgZuzj68.js +61 -0
- package/dist/dashboard/dist/assets/treemap-GDKQZRPO-DISZoPlK.js +162 -0
- package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-WhBuJ91k.js +7 -0
- package/dist/dashboard/dist/index.html +2 -2
- package/dist/src/index.js +275 -13
- package/dist/src/inference/businessRuleInference.d.ts +8 -0
- package/dist/src/inference/businessRuleInference.d.ts.map +1 -1
- package/dist/src/inference/businessRuleInference.js +52 -0
- package/dist/src/inference/routeInference.d.ts +50 -0
- package/dist/src/inference/routeInference.d.ts.map +1 -0
- package/dist/src/inference/routeInference.js +220 -0
- package/dist/src/inference/scanManifest.d.ts +35 -0
- package/dist/src/inference/scanManifest.d.ts.map +1 -0
- package/dist/src/inference/scanManifest.js +58 -0
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{s as gi,g as xi,q as Xt,p as di,a as pi,b as fi,_ as n,l as Nt,H as yi,e as mi,y as bi,F as Ct,i as Ai,D as Yt,E as wi,L as Ci,M as Bt,N as Si,K as Wt,O as zt}from"./index-k7QMCdxo.js";var mt=function(){var s=n(function(W,r,u,g){for(u=u||{},g=W.length;g--;u[W[g]]=r);return u},"o"),t=[1,10,12,14,16,18,19,21,23],i=[2,6],e=[1,3],a=[1,5],c=[1,6],d=[1,7],m=[1,5,10,12,14,16,18,19,21,23,34,35,36],b=[1,25],P=[1,26],I=[1,28],R=[1,29],L=[1,30],z=[1,31],F=[1,32],D=[1,33],V=[1,34],f=[1,35],C=[1,36],l=[1,37],M=[1,43],B=[1,42],U=[1,47],X=[1,50],h=[1,10,12,14,16,18,19,21,23,34,35,36],k=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],w=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],S=[1,64],$={trace:n(function(){},"trace"),yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:n(function(r,u,g,x,A,o,nt){var p=o.length-1;switch(A){case 5:x.setOrientation(o[p]);break;case 9:x.setDiagramTitle(o[p].text.trim());break;case 12:x.setLineData({text:"",type:"text"},o[p]);break;case 13:x.setLineData(o[p-1],o[p]);break;case 14:x.setBarData({text:"",type:"text"},o[p]);break;case 15:x.setBarData(o[p-1],o[p]);break;case 16:this.$=o[p].trim(),x.setAccTitle(this.$);break;case 17:case 18:this.$=o[p].trim(),x.setAccDescription(this.$);break;case 19:this.$=o[p-1];break;case 20:this.$=[Number(o[p-2]),...o[p]];break;case 21:this.$=[Number(o[p])];break;case 22:x.setXAxisTitle(o[p]);break;case 23:x.setXAxisTitle(o[p-1]);break;case 24:x.setXAxisTitle({type:"text",text:""});break;case 25:x.setXAxisBand(o[p]);break;case 26:x.setXAxisRangeData(Number(o[p-2]),Number(o[p]));break;case 27:this.$=o[p-1];break;case 28:this.$=[o[p-2],...o[p]];break;case 29:this.$=[o[p]];break;case 30:x.setYAxisTitle(o[p]);break;case 31:x.setYAxisTitle(o[p-1]);break;case 32:x.setYAxisTitle({type:"text",text:""});break;case 33:x.setYAxisRangeData(Number(o[p-2]),Number(o[p]));break;case 37:this.$={text:o[p],type:"text"};break;case 38:this.$={text:o[p],type:"text"};break;case 39:this.$={text:o[p],type:"markdown"};break;case 40:this.$=o[p];break;case 41:this.$=o[p-1]+""+o[p];break}},"anonymous"),table:[s(t,i,{3:1,4:2,7:4,5:e,34:a,35:c,36:d}),{1:[3]},s(t,i,{4:2,7:4,3:8,5:e,34:a,35:c,36:d}),s(t,i,{4:2,7:4,6:9,3:10,5:e,8:[1,11],34:a,35:c,36:d}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},s(m,[2,34]),s(m,[2,35]),s(m,[2,36]),{1:[2,1]},s(t,i,{4:2,7:4,3:21,5:e,34:a,35:c,36:d}),{1:[2,3]},s(m,[2,5]),s(t,[2,7],{4:22,34:a,35:c,36:d}),{11:23,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},{11:39,13:38,24:M,27:B,29:40,30:41,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},{11:45,15:44,27:U,33:46,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},{11:49,17:48,24:X,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},{11:52,17:51,24:X,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},{20:[1,53]},{22:[1,54]},s(h,[2,18]),{1:[2,2]},s(h,[2,8]),s(h,[2,9]),s(k,[2,37],{40:55,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l}),s(k,[2,38]),s(k,[2,39]),s(w,[2,40]),s(w,[2,42]),s(w,[2,43]),s(w,[2,44]),s(w,[2,45]),s(w,[2,46]),s(w,[2,47]),s(w,[2,48]),s(w,[2,49]),s(w,[2,50]),s(w,[2,51]),s(h,[2,10]),s(h,[2,22],{30:41,29:56,24:M,27:B}),s(h,[2,24]),s(h,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},s(h,[2,11]),s(h,[2,30],{33:60,27:U}),s(h,[2,32]),{31:[1,61]},s(h,[2,12]),{17:62,24:X},{25:63,27:S},s(h,[2,14]),{17:65,24:X},s(h,[2,16]),s(h,[2,17]),s(w,[2,41]),s(h,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},s(h,[2,31]),{27:[1,69]},s(h,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},s(h,[2,15]),s(h,[2,26]),s(h,[2,27]),{11:59,32:72,37:24,38:b,39:P,40:27,41:I,42:R,43:L,44:z,45:F,46:D,47:V,48:f,49:C,50:l},s(h,[2,33]),s(h,[2,19]),{25:73,27:S},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:n(function(r,u){if(u.recoverable)this.trace(r);else{var g=new Error(r);throw g.hash=u,g}},"parseError"),parse:n(function(r){var u=this,g=[0],x=[],A=[null],o=[],nt=this.table,p="",lt=0,Et=0,hi=2,It=1,li=o.slice.call(arguments,1),_=Object.create(this.lexer),Y={yy:{}};for(var dt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,dt)&&(Y.yy[dt]=this.yy[dt]);_.setInput(r,Y.yy),Y.yy.lexer=_,Y.yy.parser=this,typeof _.yylloc>"u"&&(_.yylloc={});var pt=_.yylloc;o.push(pt);var ci=_.options&&_.options.ranges;typeof Y.yy.parseError=="function"?this.parseError=Y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ui(v){g.length=g.length-2*v,A.length=A.length-v,o.length=o.length-v}n(ui,"popStack");function Vt(){var v;return v=x.pop()||_.lex()||It,typeof v!="number"&&(v instanceof Array&&(x=v,v=x.pop()),v=u.symbols_[v]||v),v}n(Vt,"lex");for(var T,H,E,ft,q={},ct,O,Mt,ut;;){if(H=g[g.length-1],this.defaultActions[H]?E=this.defaultActions[H]:((T===null||typeof T>"u")&&(T=Vt()),E=nt[H]&&nt[H][T]),typeof E>"u"||!E.length||!E[0]){var yt="";ut=[];for(ct in nt[H])this.terminals_[ct]&&ct>hi&&ut.push("'"+this.terminals_[ct]+"'");_.showPosition?yt="Parse error on line "+(lt+1)+`:
|
|
2
|
+
`+_.showPosition()+`
|
|
3
|
+
Expecting `+ut.join(", ")+", got '"+(this.terminals_[T]||T)+"'":yt="Parse error on line "+(lt+1)+": Unexpected "+(T==It?"end of input":"'"+(this.terminals_[T]||T)+"'"),this.parseError(yt,{text:_.match,token:this.terminals_[T]||T,line:_.yylineno,loc:pt,expected:ut})}if(E[0]instanceof Array&&E.length>1)throw new Error("Parse Error: multiple actions possible at state: "+H+", token: "+T);switch(E[0]){case 1:g.push(T),A.push(_.yytext),o.push(_.yylloc),g.push(E[1]),T=null,Et=_.yyleng,p=_.yytext,lt=_.yylineno,pt=_.yylloc;break;case 2:if(O=this.productions_[E[1]][1],q.$=A[A.length-O],q._$={first_line:o[o.length-(O||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(O||1)].first_column,last_column:o[o.length-1].last_column},ci&&(q._$.range=[o[o.length-(O||1)].range[0],o[o.length-1].range[1]]),ft=this.performAction.apply(q,[p,Et,lt,Y.yy,E[1],A,o].concat(li)),typeof ft<"u")return ft;O&&(g=g.slice(0,-1*O*2),A=A.slice(0,-1*O),o=o.slice(0,-1*O)),g.push(this.productions_[E[1]][0]),A.push(q.$),o.push(q._$),Mt=nt[g[g.length-2]][g[g.length-1]],g.push(Mt);break;case 3:return!0}}return!0},"parse")},Lt=function(){var W={EOF:1,parseError:n(function(u,g){if(this.yy.parser)this.yy.parser.parseError(u,g);else throw new Error(u)},"parseError"),setInput:n(function(r,u){return this.yy=u||this.yy||{},this._input=r,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:n(function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var u=r.match(/(?:\r\n?|\n).*/g);return u?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},"input"),unput:n(function(r){var u=r.length,g=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-u),this.offset-=u;var x=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),g.length-1&&(this.yylineno-=g.length-1);var A=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:g?(g.length===x.length?this.yylloc.first_column:0)+x[x.length-g.length].length-g[0].length:this.yylloc.first_column-u},this.options.ranges&&(this.yylloc.range=[A[0],A[0]+this.yyleng-u]),this.yyleng=this.yytext.length,this},"unput"),more:n(function(){return this._more=!0,this},"more"),reject:n(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
|
|
4
|
+
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:n(function(r){this.unput(this.match.slice(r))},"less"),pastInput:n(function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:n(function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:n(function(){var r=this.pastInput(),u=new Array(r.length+1).join("-");return r+this.upcomingInput()+`
|
|
5
|
+
`+u+"^"},"showPosition"),test_match:n(function(r,u){var g,x,A;if(this.options.backtrack_lexer&&(A={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(A.yylloc.range=this.yylloc.range.slice(0))),x=r[0].match(/(?:\r\n?|\n).*/g),x&&(this.yylineno+=x.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:x?x[x.length-1].length-x[x.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+r[0].length},this.yytext+=r[0],this.match+=r[0],this.matches=r,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(r[0].length),this.matched+=r[0],g=this.performAction.call(this,this.yy,this,u,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),g)return g;if(this._backtrack){for(var o in A)this[o]=A[o];return!1}return!1},"test_match"),next:n(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var r,u,g,x;this._more||(this.yytext="",this.match="");for(var A=this._currentRules(),o=0;o<A.length;o++)if(g=this._input.match(this.rules[A[o]]),g&&(!u||g[0].length>u[0].length)){if(u=g,x=o,this.options.backtrack_lexer){if(r=this.test_match(g,A[o]),r!==!1)return r;if(this._backtrack){u=!1;continue}else return!1}else if(!this.options.flex)break}return u?(r=this.test_match(u,A[x]),r!==!1?r:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text.
|
|
6
|
+
`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:n(function(){var u=this.next();return u||this.lex()},"lex"),begin:n(function(u){this.conditionStack.push(u)},"begin"),popState:n(function(){var u=this.conditionStack.length-1;return u>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:n(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:n(function(u){return u=this.conditionStack.length-1-Math.abs(u||0),u>=0?this.conditionStack[u]:"INITIAL"},"topState"),pushState:n(function(u){this.begin(u)},"pushState"),stateStackSize:n(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:n(function(u,g,x,A){switch(x){case 0:break;case 1:break;case 2:return this.popState(),34;case 3:return this.popState(),34;case 4:return 34;case 5:break;case 6:return 10;case 7:return this.pushState("acc_title"),19;case 8:return this.popState(),"acc_title_value";case 9:return this.pushState("acc_descr"),21;case 10:return this.popState(),"acc_descr_value";case 11:this.pushState("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 5;case 15:return 5;case 16:return 8;case 17:return this.pushState("axis_data"),"X_AXIS";case 18:return this.pushState("axis_data"),"Y_AXIS";case 19:return this.pushState("axis_band_data"),24;case 20:return 31;case 21:return this.pushState("data"),16;case 22:return this.pushState("data"),18;case 23:return this.pushState("data_inner"),24;case 24:return 27;case 25:return this.popState(),26;case 26:this.popState();break;case 27:this.pushState("string");break;case 28:this.popState();break;case 29:return"STR";case 30:return 24;case 31:return 26;case 32:return 43;case 33:return"COLON";case 34:return 44;case 35:return 28;case 36:return 45;case 37:return 46;case 38:return 48;case 39:return 50;case 40:return 47;case 41:return 41;case 42:return 49;case 43:return 42;case 44:break;case 45:return 35;case 46:return 36}},"anonymous"),rules:[/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:(\r?\n))/i,/^(?:(\r?\n))/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:title\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:\{)/i,/^(?:[^\}]*)/i,/^(?:xychart-beta\b)/i,/^(?:xychart\b)/i,/^(?:(?:vertical|horizontal))/i,/^(?:x-axis\b)/i,/^(?:y-axis\b)/i,/^(?:\[)/i,/^(?:-->)/i,/^(?:line\b)/i,/^(?:bar\b)/i,/^(?:\[)/i,/^(?:[+-]?(?:\d+(?:\.\d+)?|\.\d+))/i,/^(?:\])/i,/^(?:(?:`\) \{ this\.pushState\(md_string\); \}\n<md_string>\(\?:\(\?!`"\)\.\)\+ \{ return MD_STR; \}\n<md_string>\(\?:`))/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:\[)/i,/^(?:\])/i,/^(?:[A-Za-z]+)/i,/^(?::)/i,/^(?:\+)/i,/^(?:,)/i,/^(?:=)/i,/^(?:\*)/i,/^(?:#)/i,/^(?:[\_])/i,/^(?:\.)/i,/^(?:&)/i,/^(?:-)/i,/^(?:[0-9]+)/i,/^(?:\s+)/i,/^(?:;)/i,/^(?:$)/i],conditions:{data_inner:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,18,21,22,24,25,26,27,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0},data:{rules:[0,1,3,4,5,6,7,9,11,14,15,16,17,18,21,22,23,26,27,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0},axis_band_data:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,18,21,22,25,26,27,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0},axis_data:{rules:[0,1,2,4,5,6,7,9,11,14,15,16,17,18,19,20,21,22,24,26,27,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0},acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},title:{rules:[],inclusive:!1},md_string:{rules:[],inclusive:!1},string:{rules:[28,29],inclusive:!1},INITIAL:{rules:[0,1,4,5,6,7,9,11,14,15,16,17,18,21,22,26,27,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],inclusive:!0}}};return W}();$.lexer=Lt;function N(){this.yy={}}return n(N,"Parser"),N.prototype=$,$.Parser=N,new N}();mt.parser=mt;var _i=mt;function bt(s){return s.type==="bar"}n(bt,"isBarPlot");function St(s){return s.type==="band"}n(St,"isBandAxisData");function G(s){return s.type==="linear"}n(G,"isLinearAxisData");var j,Ht=(j=class{constructor(t){this.parentGroup=t}getMaxDimension(t,i){if(!this.parentGroup)return{width:t.reduce((c,d)=>Math.max(d.length,c),0)*i,height:i};const e={width:0,height:0},a=this.parentGroup.append("g").attr("visibility","hidden").attr("font-size",i);for(const c of t){const d=Si(a,1,c),m=d?d.width:c.length*i,b=d?d.height:i;e.width=Math.max(e.width,m),e.height=Math.max(e.height,b)}return a.remove(),e}},n(j,"TextDimensionCalculatorWithFont"),j),Ft=.7,Ot=.2,Q,Ut=(Q=class{constructor(t,i,e,a){this.axisConfig=t,this.title=i,this.textDimensionCalculator=e,this.axisThemeConfig=a,this.boundingRect={x:0,y:0,width:0,height:0},this.axisPosition="left",this.showTitle=!1,this.showLabel=!1,this.showTick=!1,this.showAxisLine=!1,this.outerPadding=0,this.titleTextHeight=0,this.labelTextHeight=0,this.range=[0,10],this.boundingRect={x:0,y:0,width:0,height:0},this.axisPosition="left"}setRange(t){this.range=t,this.axisPosition==="left"||this.axisPosition==="right"?this.boundingRect.height=t[1]-t[0]:this.boundingRect.width=t[1]-t[0],this.recalculateScale()}getRange(){return[this.range[0]+this.outerPadding,this.range[1]-this.outerPadding]}setAxisPosition(t){this.axisPosition=t,this.setRange(this.range)}getTickDistance(){const t=this.getRange();return Math.abs(t[0]-t[1])/this.getTickValues().length}getAxisOuterPadding(){return this.outerPadding}getLabelDimension(){return this.textDimensionCalculator.getMaxDimension(this.getTickValues().map(t=>t.toString()),this.axisConfig.labelFontSize)}recalculateOuterPaddingToDrawBar(){Ft*this.getTickDistance()>this.outerPadding*2&&(this.outerPadding=Math.floor(Ft*this.getTickDistance()/2)),this.recalculateScale()}calculateSpaceIfDrawnHorizontally(t){let i=t.height;if(this.axisConfig.showAxisLine&&i>this.axisConfig.axisLineWidth&&(i-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){const e=this.getLabelDimension(),a=Ot*t.width;this.outerPadding=Math.min(e.width/2,a);const c=e.height+this.axisConfig.labelPadding*2;this.labelTextHeight=e.height,c<=i&&(i-=c,this.showLabel=!0)}if(this.axisConfig.showTick&&i>=this.axisConfig.tickLength&&(this.showTick=!0,i-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){const e=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),a=e.height+this.axisConfig.titlePadding*2;this.titleTextHeight=e.height,a<=i&&(i-=a,this.showTitle=!0)}this.boundingRect.width=t.width,this.boundingRect.height=t.height-i}calculateSpaceIfDrawnVertical(t){let i=t.width;if(this.axisConfig.showAxisLine&&i>this.axisConfig.axisLineWidth&&(i-=this.axisConfig.axisLineWidth,this.showAxisLine=!0),this.axisConfig.showLabel){const e=this.getLabelDimension(),a=Ot*t.height;this.outerPadding=Math.min(e.height/2,a);const c=e.width+this.axisConfig.labelPadding*2;c<=i&&(i-=c,this.showLabel=!0)}if(this.axisConfig.showTick&&i>=this.axisConfig.tickLength&&(this.showTick=!0,i-=this.axisConfig.tickLength),this.axisConfig.showTitle&&this.title){const e=this.textDimensionCalculator.getMaxDimension([this.title],this.axisConfig.titleFontSize),a=e.height+this.axisConfig.titlePadding*2;this.titleTextHeight=e.height,a<=i&&(i-=a,this.showTitle=!0)}this.boundingRect.width=t.width-i,this.boundingRect.height=t.height}calculateSpace(t){return this.axisPosition==="left"||this.axisPosition==="right"?this.calculateSpaceIfDrawnVertical(t):this.calculateSpaceIfDrawnHorizontally(t),this.recalculateScale(),{width:this.boundingRect.width,height:this.boundingRect.height}}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}getDrawableElementsForLeftAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.x+this.boundingRect.width-this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["left-axis","axisl-line"],data:[{path:`M ${i},${this.boundingRect.y} L ${i},${this.boundingRect.y+this.boundingRect.height} `,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["left-axis","label"],data:this.getTickValues().map(i=>({text:i.toString(),x:this.boundingRect.x+this.boundingRect.width-(this.showLabel?this.axisConfig.labelPadding:0)-(this.showTick?this.axisConfig.tickLength:0)-(this.showAxisLine?this.axisConfig.axisLineWidth:0),y:this.getScaleValue(i),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"middle",horizontalPos:"right"}))}),this.showTick){const i=this.boundingRect.x+this.boundingRect.width-(this.showAxisLine?this.axisConfig.axisLineWidth:0);t.push({type:"path",groupTexts:["left-axis","ticks"],data:this.getTickValues().map(e=>({path:`M ${i},${this.getScaleValue(e)} L ${i-this.axisConfig.tickLength},${this.getScaleValue(e)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&t.push({type:"text",groupTexts:["left-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.axisConfig.titlePadding,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:270,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElementsForBottomAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.y+this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["bottom-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${i} L ${this.boundingRect.x+this.boundingRect.width},${i}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["bottom-axis","label"],data:this.getTickValues().map(i=>({text:i.toString(),x:this.getScaleValue(i),y:this.boundingRect.y+this.axisConfig.labelPadding+(this.showTick?this.axisConfig.tickLength:0)+(this.showAxisLine?this.axisConfig.axisLineWidth:0),fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}))}),this.showTick){const i=this.boundingRect.y+(this.showAxisLine?this.axisConfig.axisLineWidth:0);t.push({type:"path",groupTexts:["bottom-axis","ticks"],data:this.getTickValues().map(e=>({path:`M ${this.getScaleValue(e)},${i} L ${this.getScaleValue(e)},${i+this.axisConfig.tickLength}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&t.push({type:"text",groupTexts:["bottom-axis","title"],data:[{text:this.title,x:this.range[0]+(this.range[1]-this.range[0])/2,y:this.boundingRect.y+this.boundingRect.height-this.axisConfig.titlePadding-this.titleTextHeight,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElementsForTopAxis(){const t=[];if(this.showAxisLine){const i=this.boundingRect.y+this.boundingRect.height-this.axisConfig.axisLineWidth/2;t.push({type:"path",groupTexts:["top-axis","axis-line"],data:[{path:`M ${this.boundingRect.x},${i} L ${this.boundingRect.x+this.boundingRect.width},${i}`,strokeFill:this.axisThemeConfig.axisLineColor,strokeWidth:this.axisConfig.axisLineWidth}]})}if(this.showLabel&&t.push({type:"text",groupTexts:["top-axis","label"],data:this.getTickValues().map(i=>({text:i.toString(),x:this.getScaleValue(i),y:this.boundingRect.y+(this.showTitle?this.titleTextHeight+this.axisConfig.titlePadding*2:0)+this.axisConfig.labelPadding,fill:this.axisThemeConfig.labelColor,fontSize:this.axisConfig.labelFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}))}),this.showTick){const i=this.boundingRect.y;t.push({type:"path",groupTexts:["top-axis","ticks"],data:this.getTickValues().map(e=>({path:`M ${this.getScaleValue(e)},${i+this.boundingRect.height-(this.showAxisLine?this.axisConfig.axisLineWidth:0)} L ${this.getScaleValue(e)},${i+this.boundingRect.height-this.axisConfig.tickLength-(this.showAxisLine?this.axisConfig.axisLineWidth:0)}`,strokeFill:this.axisThemeConfig.tickColor,strokeWidth:this.axisConfig.tickWidth}))})}return this.showTitle&&t.push({type:"text",groupTexts:["top-axis","title"],data:[{text:this.title,x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.axisConfig.titlePadding,fill:this.axisThemeConfig.titleColor,fontSize:this.axisConfig.titleFontSize,rotation:0,verticalPos:"top",horizontalPos:"center"}]}),t}getDrawableElements(){if(this.axisPosition==="left")return this.getDrawableElementsForLeftAxis();if(this.axisPosition==="right")throw Error("Drawing of right axis is not implemented");return this.axisPosition==="bottom"?this.getDrawableElementsForBottomAxis():this.axisPosition==="top"?this.getDrawableElementsForTopAxis():[]}},n(Q,"BaseAxis"),Q),K,ki=(K=class extends Ut{constructor(t,i,e,a,c){super(t,a,c,i),this.categories=e,this.scale=Bt().domain(this.categories).range(this.getRange())}setRange(t){super.setRange(t)}recalculateScale(){this.scale=Bt().domain(this.categories).range(this.getRange()).paddingInner(1).paddingOuter(0).align(.5),Nt.trace("BandAxis axis final categories, range: ",this.categories,this.getRange())}getTickValues(){return this.categories}getScaleValue(t){return this.scale(t)??this.getRange()[0]}},n(K,"BandAxis"),K),Z,Ti=(Z=class extends Ut{constructor(t,i,e,a,c){super(t,a,c,i),this.domain=e,this.scale=Wt().domain(this.domain).range(this.getRange())}getTickValues(){return this.scale.ticks()}recalculateScale(){const t=[...this.domain];this.axisPosition==="left"&&t.reverse(),this.scale=Wt().domain(t).range(this.getRange())}getScaleValue(t){return this.scale(t)}},n(Z,"LinearAxis"),Z);function At(s,t,i,e){const a=new Ht(e);return St(s)?new ki(t,i,s.categories,s.title,a):new Ti(t,i,[s.min,s.max],s.title,a)}n(At,"getAxis");var J,Ri=(J=class{constructor(t,i,e,a){this.textDimensionCalculator=t,this.chartConfig=i,this.chartData=e,this.chartThemeConfig=a,this.boundingRect={x:0,y:0,width:0,height:0},this.showChartTitle=!1}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}calculateSpace(t){const i=this.textDimensionCalculator.getMaxDimension([this.chartData.title],this.chartConfig.titleFontSize),e=Math.max(i.width,t.width),a=i.height+2*this.chartConfig.titlePadding;return i.width<=e&&i.height<=a&&this.chartConfig.showTitle&&this.chartData.title&&(this.boundingRect.width=e,this.boundingRect.height=a,this.showChartTitle=!0),{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){const t=[];return this.showChartTitle&&t.push({groupTexts:["chart-title"],type:"text",data:[{fontSize:this.chartConfig.titleFontSize,text:this.chartData.title,verticalPos:"middle",horizontalPos:"center",x:this.boundingRect.x+this.boundingRect.width/2,y:this.boundingRect.y+this.boundingRect.height/2,fill:this.chartThemeConfig.titleColor,rotation:0}]}),t}},n(J,"ChartTitle"),J);function $t(s,t,i,e){const a=new Ht(e);return new Ri(a,s,t,i)}n($t,"getChartTitleComponent");var tt,Di=(tt=class{constructor(t,i,e,a,c){this.plotData=t,this.xAxis=i,this.yAxis=e,this.orientation=a,this.plotIndex=c}getDrawableElement(){const t=this.plotData.data.map(e=>[this.xAxis.getScaleValue(e[0]),this.yAxis.getScaleValue(e[1])]);let i;return this.orientation==="horizontal"?i=zt().y(e=>e[0]).x(e=>e[1])(t):i=zt().x(e=>e[0]).y(e=>e[1])(t),i?[{groupTexts:["plot",`line-plot-${this.plotIndex}`],type:"path",data:[{path:i,strokeFill:this.plotData.strokeFill,strokeWidth:this.plotData.strokeWidth}]}]:[]}},n(tt,"LinePlot"),tt),it,vi=(it=class{constructor(t,i,e,a,c,d){this.barData=t,this.boundingRect=i,this.xAxis=e,this.yAxis=a,this.orientation=c,this.plotIndex=d}getDrawableElement(){const t=this.barData.data.map(c=>[this.xAxis.getScaleValue(c[0]),this.yAxis.getScaleValue(c[1])]),e=Math.min(this.xAxis.getAxisOuterPadding()*2,this.xAxis.getTickDistance())*(1-.05),a=e/2;return this.orientation==="horizontal"?[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:t.map(c=>({x:this.boundingRect.x,y:c[0]-a,height:e,width:c[1]-this.boundingRect.x,fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill}))}]:[{groupTexts:["plot",`bar-plot-${this.plotIndex}`],type:"rect",data:t.map(c=>({x:c[0]-a,y:c[1],width:e,height:this.boundingRect.y+this.boundingRect.height-c[1],fill:this.barData.fill,strokeWidth:0,strokeFill:this.barData.fill}))}]}},n(it,"BarPlot"),it),et,Pi=(et=class{constructor(t,i,e){this.chartConfig=t,this.chartData=i,this.chartThemeConfig=e,this.boundingRect={x:0,y:0,width:0,height:0}}setAxes(t,i){this.xAxis=t,this.yAxis=i}setBoundingBoxXY(t){this.boundingRect.x=t.x,this.boundingRect.y=t.y}calculateSpace(t){return this.boundingRect.width=t.width,this.boundingRect.height=t.height,{width:this.boundingRect.width,height:this.boundingRect.height}}getDrawableElements(){if(!(this.xAxis&&this.yAxis))throw Error("Axes must be passed to render Plots");const t=[];for(const[i,e]of this.chartData.plots.entries())switch(e.type){case"line":{const a=new Di(e,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,i);t.push(...a.getDrawableElement())}break;case"bar":{const a=new vi(e,this.boundingRect,this.xAxis,this.yAxis,this.chartConfig.chartOrientation,i);t.push(...a.getDrawableElement())}break}return t}},n(et,"BasePlot"),et);function qt(s,t,i){return new Pi(s,t,i)}n(qt,"getPlotComponent");var st,Li=(st=class{constructor(t,i,e,a){this.chartConfig=t,this.chartData=i,this.componentStore={title:$t(t,i,e,a),plot:qt(t,i,e),xAxis:At(i.xAxis,t.xAxis,{titleColor:e.xAxisTitleColor,labelColor:e.xAxisLabelColor,tickColor:e.xAxisTickColor,axisLineColor:e.xAxisLineColor},a),yAxis:At(i.yAxis,t.yAxis,{titleColor:e.yAxisTitleColor,labelColor:e.yAxisLabelColor,tickColor:e.yAxisTickColor,axisLineColor:e.yAxisLineColor},a)}}calculateVerticalSpace(){let t=this.chartConfig.width,i=this.chartConfig.height,e=0,a=0,c=Math.floor(t*this.chartConfig.plotReservedSpacePercent/100),d=Math.floor(i*this.chartConfig.plotReservedSpacePercent/100),m=this.componentStore.plot.calculateSpace({width:c,height:d});t-=m.width,i-=m.height,m=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:i}),a=m.height,i-=m.height,this.componentStore.xAxis.setAxisPosition("bottom"),m=this.componentStore.xAxis.calculateSpace({width:t,height:i}),i-=m.height,this.componentStore.yAxis.setAxisPosition("left"),m=this.componentStore.yAxis.calculateSpace({width:t,height:i}),e=m.width,t-=m.width,t>0&&(c+=t,t=0),i>0&&(d+=i,i=0),this.componentStore.plot.calculateSpace({width:c,height:d}),this.componentStore.plot.setBoundingBoxXY({x:e,y:a}),this.componentStore.xAxis.setRange([e,e+c]),this.componentStore.xAxis.setBoundingBoxXY({x:e,y:a+d}),this.componentStore.yAxis.setRange([a,a+d]),this.componentStore.yAxis.setBoundingBoxXY({x:0,y:a}),this.chartData.plots.some(b=>bt(b))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateHorizontalSpace(){let t=this.chartConfig.width,i=this.chartConfig.height,e=0,a=0,c=0,d=Math.floor(t*this.chartConfig.plotReservedSpacePercent/100),m=Math.floor(i*this.chartConfig.plotReservedSpacePercent/100),b=this.componentStore.plot.calculateSpace({width:d,height:m});t-=b.width,i-=b.height,b=this.componentStore.title.calculateSpace({width:this.chartConfig.width,height:i}),e=b.height,i-=b.height,this.componentStore.xAxis.setAxisPosition("left"),b=this.componentStore.xAxis.calculateSpace({width:t,height:i}),t-=b.width,a=b.width,this.componentStore.yAxis.setAxisPosition("top"),b=this.componentStore.yAxis.calculateSpace({width:t,height:i}),i-=b.height,c=e+b.height,t>0&&(d+=t,t=0),i>0&&(m+=i,i=0),this.componentStore.plot.calculateSpace({width:d,height:m}),this.componentStore.plot.setBoundingBoxXY({x:a,y:c}),this.componentStore.yAxis.setRange([a,a+d]),this.componentStore.yAxis.setBoundingBoxXY({x:a,y:e}),this.componentStore.xAxis.setRange([c,c+m]),this.componentStore.xAxis.setBoundingBoxXY({x:0,y:c}),this.chartData.plots.some(P=>bt(P))&&this.componentStore.xAxis.recalculateOuterPaddingToDrawBar()}calculateSpace(){this.chartConfig.chartOrientation==="horizontal"?this.calculateHorizontalSpace():this.calculateVerticalSpace()}getDrawableElement(){this.calculateSpace();const t=[];this.componentStore.plot.setAxes(this.componentStore.xAxis,this.componentStore.yAxis);for(const i of Object.values(this.componentStore))t.push(...i.getDrawableElements());return t}},n(st,"Orchestrator"),st),at,Ei=(at=class{static build(t,i,e,a){return new Li(t,i,e,a).getDrawableElement()}},n(at,"XYChartBuilder"),at),ot=0,Gt,rt=Tt(),ht=kt(),y=Rt(),wt=ht.plotColorPalette.split(",").map(s=>s.trim()),gt=!1,_t=!1;function kt(){const s=Ci(),t=Ct();return Yt(s.xyChart,t.themeVariables.xyChart)}n(kt,"getChartDefaultThemeConfig");function Tt(){const s=Ct();return Yt(wi.xyChart,s.xyChart)}n(Tt,"getChartDefaultConfig");function Rt(){return{yAxis:{type:"linear",title:"",min:1/0,max:-1/0},xAxis:{type:"band",title:"",categories:[]},title:"",plots:[]}}n(Rt,"getChartDefaultData");function xt(s){const t=Ct();return Ai(s.trim(),t)}n(xt,"textSanitizer");function jt(s){Gt=s}n(jt,"setTmpSVGG");function Qt(s){s==="horizontal"?rt.chartOrientation="horizontal":rt.chartOrientation="vertical"}n(Qt,"setOrientation");function Kt(s){y.xAxis.title=xt(s.text)}n(Kt,"setXAxisTitle");function Dt(s,t){y.xAxis={type:"linear",title:y.xAxis.title,min:s,max:t},gt=!0}n(Dt,"setXAxisRangeData");function Zt(s){y.xAxis={type:"band",title:y.xAxis.title,categories:s.map(t=>xt(t.text))},gt=!0}n(Zt,"setXAxisBand");function Jt(s){y.yAxis.title=xt(s.text)}n(Jt,"setYAxisTitle");function ti(s,t){y.yAxis={type:"linear",title:y.yAxis.title,min:s,max:t},_t=!0}n(ti,"setYAxisRangeData");function ii(s){const t=Math.min(...s),i=Math.max(...s),e=G(y.yAxis)?y.yAxis.min:1/0,a=G(y.yAxis)?y.yAxis.max:-1/0;y.yAxis={type:"linear",title:y.yAxis.title,min:Math.min(e,t),max:Math.max(a,i)}}n(ii,"setYAxisRangeFromPlotData");function vt(s){let t=[];if(s.length===0)return t;if(!gt){const i=G(y.xAxis)?y.xAxis.min:1/0,e=G(y.xAxis)?y.xAxis.max:-1/0;Dt(Math.min(i,1),Math.max(e,s.length))}if(_t||ii(s),St(y.xAxis)&&(t=y.xAxis.categories.map((i,e)=>[i,s[e]])),G(y.xAxis)){const i=y.xAxis.min,e=y.xAxis.max,a=(e-i)/(s.length-1),c=[];for(let d=i;d<=e;d+=a)c.push(`${d}`);t=c.map((d,m)=>[d,s[m]])}return t}n(vt,"transformDataWithoutCategory");function Pt(s){return wt[s===0?0:s%wt.length]}n(Pt,"getPlotColorFromPalette");function ei(s,t){const i=vt(t);y.plots.push({type:"line",strokeFill:Pt(ot),strokeWidth:2,data:i}),ot++}n(ei,"setLineData");function si(s,t){const i=vt(t);y.plots.push({type:"bar",fill:Pt(ot),data:i}),ot++}n(si,"setBarData");function ai(){if(y.plots.length===0)throw Error("No Plot to render, please provide a plot with some data");return y.title=Xt(),Ei.build(rt,y,ht,Gt)}n(ai,"getDrawableElem");function ni(){return ht}n(ni,"getChartThemeConfig");function oi(){return rt}n(oi,"getChartConfig");function ri(){return y}n(ri,"getXYChartData");var Ii=n(function(){bi(),ot=0,rt=Tt(),y=Rt(),ht=kt(),wt=ht.plotColorPalette.split(",").map(s=>s.trim()),gt=!1,_t=!1},"clear"),Vi={getDrawableElem:ai,clear:Ii,setAccTitle:fi,getAccTitle:pi,setDiagramTitle:di,getDiagramTitle:Xt,getAccDescription:xi,setAccDescription:gi,setOrientation:Qt,setXAxisTitle:Kt,setXAxisRangeData:Dt,setXAxisBand:Zt,setYAxisTitle:Jt,setYAxisRangeData:ti,setLineData:ei,setBarData:si,setTmpSVGG:jt,getChartThemeConfig:ni,getChartConfig:oi,getXYChartData:ri},Mi=n((s,t,i,e)=>{const a=e.db,c=a.getChartThemeConfig(),d=a.getChartConfig(),m=a.getXYChartData().plots[0].data.map(f=>f[1]);function b(f){return f==="top"?"text-before-edge":"middle"}n(b,"getDominantBaseLine");function P(f){return f==="left"?"start":f==="right"?"end":"middle"}n(P,"getTextAnchor");function I(f){return`translate(${f.x}, ${f.y}) rotate(${f.rotation||0})`}n(I,"getTextTransformation"),Nt.debug(`Rendering xychart chart
|
|
7
|
+
`+s);const R=yi(t),L=R.append("g").attr("class","main"),z=L.append("rect").attr("width",d.width).attr("height",d.height).attr("class","background");mi(R,d.height,d.width,!0),R.attr("viewBox",`0 0 ${d.width} ${d.height}`),z.attr("fill",c.backgroundColor),a.setTmpSVGG(R.append("g").attr("class","mermaid-tmp-group"));const F=a.getDrawableElem(),D={};function V(f){let C=L,l="";for(const[M]of f.entries()){let B=L;M>0&&D[l]&&(B=D[l]),l+=f[M],C=D[l],C||(C=D[l]=B.append("g").attr("class",f[M]))}return C}n(V,"getGroup");for(const f of F){if(f.data.length===0)continue;const C=V(f.groupTexts);switch(f.type){case"rect":if(C.selectAll("rect").data(f.data).enter().append("rect").attr("x",l=>l.x).attr("y",l=>l.y).attr("width",l=>l.width).attr("height",l=>l.height).attr("fill",l=>l.fill).attr("stroke",l=>l.strokeFill).attr("stroke-width",l=>l.strokeWidth),d.showDataLabel)if(d.chartOrientation==="horizontal"){let l=function(h,k){const{data:w,label:S}=h;return k*S.length*M<=w.width-10};n(l,"fitsHorizontally");const M=.7,B=f.data.map((h,k)=>({data:h,label:m[k].toString()})).filter(h=>h.data.width>0&&h.data.height>0),U=B.map(h=>{const{data:k}=h;let w=k.height*.7;for(;!l(h,w)&&w>0;)w-=1;return w}),X=Math.floor(Math.min(...U));C.selectAll("text").data(B).enter().append("text").attr("x",h=>h.data.x+h.data.width-10).attr("y",h=>h.data.y+h.data.height/2).attr("text-anchor","end").attr("dominant-baseline","middle").attr("fill","black").attr("font-size",`${X}px`).text(h=>h.label)}else{let l=function(h,k,w){const{data:S,label:$}=h,N=k*$.length*.7,W=S.x+S.width/2,r=W-N/2,u=W+N/2,g=r>=S.x&&u<=S.x+S.width,x=S.y+w+k<=S.y+S.height;return g&&x};n(l,"fitsInBar");const M=10,B=f.data.map((h,k)=>({data:h,label:m[k].toString()})).filter(h=>h.data.width>0&&h.data.height>0),U=B.map(h=>{const{data:k,label:w}=h;let S=k.width/(w.length*.7);for(;!l(h,S,M)&&S>0;)S-=1;return S}),X=Math.floor(Math.min(...U));C.selectAll("text").data(B).enter().append("text").attr("x",h=>h.data.x+h.data.width/2).attr("y",h=>h.data.y+M).attr("text-anchor","middle").attr("dominant-baseline","hanging").attr("fill","black").attr("font-size",`${X}px`).text(h=>h.label)}break;case"text":C.selectAll("text").data(f.data).enter().append("text").attr("x",0).attr("y",0).attr("fill",l=>l.fill).attr("font-size",l=>l.fontSize).attr("dominant-baseline",l=>b(l.verticalPos)).attr("text-anchor",l=>P(l.horizontalPos)).attr("transform",l=>I(l)).text(l=>l.text);break;case"path":C.selectAll("path").data(f.data).enter().append("path").attr("d",l=>l.path).attr("fill",l=>l.fill?l.fill:"none").attr("stroke",l=>l.strokeFill).attr("stroke-width",l=>l.strokeWidth);break}}},"draw"),Bi={draw:Mi},zi={parser:_i,db:Vi,renderer:Bi};export{zi as diagram};
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>API Coverage Analyzer Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-k7QMCdxo.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-HrRX8fCW.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/dist/src/index.js
CHANGED
|
@@ -55,14 +55,19 @@ const index_3 = require("./intelligence/index");
|
|
|
55
55
|
const observability_2 = require("./observability");
|
|
56
56
|
const buildSummary_1 = require("./summary/buildSummary");
|
|
57
57
|
const prSummary_1 = require("./summary/prSummary");
|
|
58
|
+
const summaryTypes_1 = require("./summary/summaryTypes");
|
|
58
59
|
const astAnalysisOrchestrator_1 = require("./ast/astAnalysisOrchestrator");
|
|
59
60
|
const projectDiscovery_1 = require("./discovery/projectDiscovery");
|
|
60
61
|
const businessRuleInference_1 = require("./inference/businessRuleInference");
|
|
61
62
|
const integrationFlowInference_1 = require("./inference/integrationFlowInference");
|
|
63
|
+
const routeInference_1 = require("./inference/routeInference");
|
|
64
|
+
const scanManifest_1 = require("./inference/scanManifest");
|
|
62
65
|
const serveDashboard_1 = require("./serveDashboard");
|
|
63
66
|
// Register all language AST analyzers at startup.
|
|
64
67
|
// This side-effect import ensures each language module's registerAnalyzer() call runs.
|
|
65
68
|
(0, astAnalysisOrchestrator_1.registerAllAnalyzers)();
|
|
69
|
+
/** Keywords that indicate a test is exercising an error/failure path. */
|
|
70
|
+
const ERROR_TEST_KEYWORDS = ['error', 'fail', 'throw', 'exception', 'reject', 'invalid', 'blank', 'missing'];
|
|
66
71
|
const program = new commander_1.Command();
|
|
67
72
|
program
|
|
68
73
|
.name('api-tests-coverage-analyzer')
|
|
@@ -1422,10 +1427,34 @@ program
|
|
|
1422
1427
|
// ── 4. Full coverage analysis → coverage-summary.json ─────────────────
|
|
1423
1428
|
const allCoverageResults = [];
|
|
1424
1429
|
const fsMod = require('fs');
|
|
1430
|
+
// When test files are explicitly discovered, use them directly.
|
|
1431
|
+
// Otherwise fall back to a test-file-pattern glob (avoids scanning node_modules
|
|
1432
|
+
// or the entire project tree, which can hang on large repositories).
|
|
1425
1433
|
const testsGlob = artifacts.testFiles.length > 0
|
|
1426
1434
|
? '{' + artifacts.testFiles.join(',') + '}'
|
|
1427
|
-
: path.join(rootDir, '**', '
|
|
1435
|
+
: path.join(rootDir, '**', '*.{test,spec}.{js,ts,jsx,tsx,mjs,cjs,py,rb}');
|
|
1428
1436
|
const detectedLanguages = artifacts.languages;
|
|
1437
|
+
// Pre-compute test entries once from the discovered test files.
|
|
1438
|
+
// These are reused for endpoint, error, and business-rule coverage matching
|
|
1439
|
+
// (avoids multiple glob expansions which can hang on large projects).
|
|
1440
|
+
const TEST_DECL_RE = /\b(?:test|it)\s*\(\s*(['"`])([\s\S]*?)\1/g;
|
|
1441
|
+
const testEntries = artifacts.testFiles.flatMap((tf) => {
|
|
1442
|
+
let content = '';
|
|
1443
|
+
try {
|
|
1444
|
+
content = fsMod.readFileSync(tf, 'utf-8');
|
|
1445
|
+
}
|
|
1446
|
+
catch {
|
|
1447
|
+
return [];
|
|
1448
|
+
}
|
|
1449
|
+
const descriptions = [];
|
|
1450
|
+
const contentLower = content.toLowerCase();
|
|
1451
|
+
let m;
|
|
1452
|
+
TEST_DECL_RE.lastIndex = 0;
|
|
1453
|
+
while ((m = TEST_DECL_RE.exec(content)) !== null) {
|
|
1454
|
+
descriptions.push(m[2].toLowerCase());
|
|
1455
|
+
}
|
|
1456
|
+
return [{ file: tf, contentLower, descriptions }];
|
|
1457
|
+
});
|
|
1429
1458
|
if (artifacts.specs.length > 0) {
|
|
1430
1459
|
for (const specPath of artifacts.specs) {
|
|
1431
1460
|
// ── 4a. Endpoint coverage ───────────────────────────────────────────
|
|
@@ -1499,7 +1528,140 @@ program
|
|
|
1499
1528
|
}
|
|
1500
1529
|
}
|
|
1501
1530
|
else {
|
|
1502
|
-
warnings.push('No API spec files found; endpoint/
|
|
1531
|
+
warnings.push('No API spec files found; attempting route inference for endpoint/error coverage.');
|
|
1532
|
+
// ── 4a-alt. Inferred route endpoint coverage ──────────────────────────
|
|
1533
|
+
try {
|
|
1534
|
+
const routeResult = (0, routeInference_1.inferRoutes)(artifacts.serviceFiles);
|
|
1535
|
+
if (routeResult.routes.length > 0) {
|
|
1536
|
+
const routesPath = (0, routeInference_1.writeInferredRoutes)(routeResult, reportsDir);
|
|
1537
|
+
console.log(`\nRoute Inference`);
|
|
1538
|
+
console.log(` Routes detected in service code: ${routeResult.routes.length}`);
|
|
1539
|
+
console.log(` Written to: ${routesPath}`);
|
|
1540
|
+
console.log(`\nAnalyzing endpoint coverage (from inferred routes)...`);
|
|
1541
|
+
const endpointItems = routeResult.routes.map((route) => {
|
|
1542
|
+
var _a;
|
|
1543
|
+
const pathSegments = route.path.split('/').filter((s) => s.length > 1 && !s.startsWith(':'));
|
|
1544
|
+
const method = route.method.toLowerCase();
|
|
1545
|
+
// Leaf path segment is the most specific identifier (e.g., "comments", "favorite", "feed")
|
|
1546
|
+
const leafSegment = (_a = pathSegments[pathSegments.length - 1]) !== null && _a !== void 0 ? _a : '';
|
|
1547
|
+
const matchedTests = [];
|
|
1548
|
+
for (const { file, contentLower, descriptions } of testEntries) {
|
|
1549
|
+
let matched = false;
|
|
1550
|
+
// Priority 1: handler function name appears in test file imports/calls
|
|
1551
|
+
if (route.handlerFunction) {
|
|
1552
|
+
const fnLower = route.handlerFunction.toLowerCase();
|
|
1553
|
+
if (contentLower.includes(fnLower)) {
|
|
1554
|
+
matched = true;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
// Priority 2: test description mentions method + leaf path segment
|
|
1558
|
+
if (!matched && leafSegment.length > 2) {
|
|
1559
|
+
matched = descriptions.some((desc) => desc.includes(method) && desc.includes(leafSegment));
|
|
1560
|
+
}
|
|
1561
|
+
// Priority 3: test description mentions the exact path
|
|
1562
|
+
if (!matched && route.path.length >= 1) {
|
|
1563
|
+
matched = descriptions.some((desc) => desc.includes(route.path.toLowerCase()));
|
|
1564
|
+
}
|
|
1565
|
+
// Priority 4: test file directly calls the URL path (e.g., axios.get('/articles'))
|
|
1566
|
+
if (!matched && pathSegments.length > 0) {
|
|
1567
|
+
// Check for full path string in file (e.g., axios.get('/articles/feed'))
|
|
1568
|
+
const quotedPathPattern = new RegExp(`['"\`]${route.path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}['"\`]`);
|
|
1569
|
+
if (quotedPathPattern.test(contentLower)) {
|
|
1570
|
+
matched = true;
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
if (matched) {
|
|
1574
|
+
matchedTests.push(path.basename(file));
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
const covered = matchedTests.length > 0;
|
|
1578
|
+
return {
|
|
1579
|
+
id: `${route.method.toUpperCase()} ${route.path}`,
|
|
1580
|
+
covered,
|
|
1581
|
+
matchedTests,
|
|
1582
|
+
handler_function: route.handlerFunction,
|
|
1583
|
+
source_file: route.sourceFile,
|
|
1584
|
+
line_number: route.lineNumber,
|
|
1585
|
+
};
|
|
1586
|
+
});
|
|
1587
|
+
const coveredCount = endpointItems.filter((i) => i.covered).length;
|
|
1588
|
+
const pct = endpointItems.length > 0 ? Math.round((coveredCount / endpointItems.length) * 100) : 0;
|
|
1589
|
+
const endpointResult = {
|
|
1590
|
+
type: 'endpoint',
|
|
1591
|
+
totalItems: endpointItems.length,
|
|
1592
|
+
coveredItems: coveredCount,
|
|
1593
|
+
coveragePercent: pct,
|
|
1594
|
+
details: {
|
|
1595
|
+
total: endpointItems.length,
|
|
1596
|
+
covered: coveredCount,
|
|
1597
|
+
percentage: pct,
|
|
1598
|
+
items: endpointItems,
|
|
1599
|
+
source: 'inferred',
|
|
1600
|
+
},
|
|
1601
|
+
};
|
|
1602
|
+
allCoverageResults.push(endpointResult);
|
|
1603
|
+
console.log(` ${coveredCount}/${endpointItems.length} inferred routes have test coverage (${pct}%)`);
|
|
1604
|
+
// ── 4c-alt. Error coverage from inferred routes + rules ──────────
|
|
1605
|
+
if (inferredRulesResult && inferredRulesResult.rules.length > 0) {
|
|
1606
|
+
console.log(`\nAnalyzing error coverage (from inferred business rules)...`);
|
|
1607
|
+
const errorCandidateRules = inferredRulesResult.rules.filter((r) => r.type === 'validation' || r.type === 'business_logic');
|
|
1608
|
+
const errorItems = errorCandidateRules.map((rule) => {
|
|
1609
|
+
var _a;
|
|
1610
|
+
const matchedTestDescriptions = [];
|
|
1611
|
+
for (const { file, descriptions } of testEntries) {
|
|
1612
|
+
// Match at TEST DESCRIPTION level, not file level
|
|
1613
|
+
// Require: description contains an error indicator + at least one specific keyword
|
|
1614
|
+
const specificKws = (_a = rule.specificKeywords) !== null && _a !== void 0 ? _a : [];
|
|
1615
|
+
const matchingDescs = descriptions.filter((desc) => {
|
|
1616
|
+
const hasErrorKeyword = ERROR_TEST_KEYWORDS.some((kw) => desc.includes(kw));
|
|
1617
|
+
if (!hasErrorKeyword)
|
|
1618
|
+
return false;
|
|
1619
|
+
// If we have specific keywords, at least one must match in the description
|
|
1620
|
+
if (specificKws.length > 0) {
|
|
1621
|
+
return specificKws.some((kw) => desc.includes(kw.toLowerCase()));
|
|
1622
|
+
}
|
|
1623
|
+
// No specific keywords — use handler function name as fallback
|
|
1624
|
+
return true;
|
|
1625
|
+
});
|
|
1626
|
+
if (matchingDescs.length > 0) {
|
|
1627
|
+
matchedTestDescriptions.push(...matchingDescs.map((d) => `[${path.basename(file)}] ${d}`));
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
return {
|
|
1631
|
+
id: rule.id,
|
|
1632
|
+
description: rule.condition,
|
|
1633
|
+
covered: matchedTestDescriptions.length > 0,
|
|
1634
|
+
matchedTests: matchedTestDescriptions,
|
|
1635
|
+
source_location: rule.source_location,
|
|
1636
|
+
code_snippet: rule.code_snippet,
|
|
1637
|
+
};
|
|
1638
|
+
});
|
|
1639
|
+
const errorCovered = errorItems.filter((i) => i.covered).length;
|
|
1640
|
+
const errorPct = errorItems.length > 0 ? Math.round((errorCovered / errorItems.length) * 100) : 0;
|
|
1641
|
+
const errorResult = {
|
|
1642
|
+
type: 'error',
|
|
1643
|
+
totalItems: errorItems.length,
|
|
1644
|
+
coveredItems: errorCovered,
|
|
1645
|
+
coveragePercent: errorPct,
|
|
1646
|
+
details: {
|
|
1647
|
+
total: errorItems.length,
|
|
1648
|
+
covered: errorCovered,
|
|
1649
|
+
percentage: errorPct,
|
|
1650
|
+
items: errorItems,
|
|
1651
|
+
source: 'inferred',
|
|
1652
|
+
},
|
|
1653
|
+
};
|
|
1654
|
+
allCoverageResults.push(errorResult);
|
|
1655
|
+
console.log(` ${errorCovered}/${errorItems.length} inferred error scenarios have test coverage (${errorPct}%)`);
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
warnings.push('No routes detected in service files; endpoint coverage skipped.');
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
catch (err) {
|
|
1663
|
+
warnings.push(`Route/error inference failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1664
|
+
}
|
|
1503
1665
|
}
|
|
1504
1666
|
// ── 4d. Business rules coverage ─────────────────────────────────────────
|
|
1505
1667
|
const businessRulesYaml = path.join(rootDir, 'business-rules.yaml');
|
|
@@ -1525,22 +1687,29 @@ program
|
|
|
1525
1687
|
}
|
|
1526
1688
|
}
|
|
1527
1689
|
else if (inferredRulesResult && inferredRulesResult.rules.length > 0) {
|
|
1528
|
-
// Auto-inferred:
|
|
1690
|
+
// Auto-inferred: use specificKeywords from rule for accurate test matching.
|
|
1691
|
+
// Reuse the testEntries already computed for endpoint coverage — avoids
|
|
1692
|
+
// a second glob expansion (which can be slow/hang on large projects).
|
|
1529
1693
|
try {
|
|
1530
1694
|
console.log(`\nAnalyzing business rules coverage (from inferred rules)...`);
|
|
1531
1695
|
const syntheticRules = inferredRulesResult.rules.map((r) => {
|
|
1532
|
-
var _a;
|
|
1533
1696
|
const kwSet = new Set();
|
|
1534
|
-
//
|
|
1535
|
-
r.
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1697
|
+
// Use specificKeywords extracted from the condition (most accurate)
|
|
1698
|
+
if (r.specificKeywords && r.specificKeywords.length > 0) {
|
|
1699
|
+
r.specificKeywords.forEach((kw) => { if (!businessRuleInference_1.KEYWORD_STOP_WORDS.has(kw))
|
|
1700
|
+
kwSet.add(kw); });
|
|
1701
|
+
}
|
|
1702
|
+
else {
|
|
1703
|
+
// Fallback: words from rule name only (filter stop words)
|
|
1704
|
+
r.name.toLowerCase().split(/[-_\s]+/).forEach((w) => {
|
|
1705
|
+
if (w.length > 2 && !businessRuleInference_1.KEYWORD_STOP_WORDS.has(w))
|
|
1706
|
+
kwSet.add(w);
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1540
1709
|
// Non-trivial path segments from endpoint
|
|
1541
1710
|
if (r.endpoint) {
|
|
1542
1711
|
r.endpoint.toLowerCase().split(/[/.\s:]+/)
|
|
1543
|
-
.forEach((w) => { if (w.length > 2 && !/^(api|v\d)$/.test(w))
|
|
1712
|
+
.forEach((w) => { if (w.length > 2 && !/^(api|v\d)$/.test(w) && !businessRuleInference_1.KEYWORD_STOP_WORDS.has(w))
|
|
1544
1713
|
kwSet.add(w); });
|
|
1545
1714
|
}
|
|
1546
1715
|
return {
|
|
@@ -1551,14 +1720,46 @@ program
|
|
|
1551
1720
|
scenarios: [],
|
|
1552
1721
|
};
|
|
1553
1722
|
});
|
|
1554
|
-
|
|
1723
|
+
// Match rules against the testEntries already built for endpoint coverage.
|
|
1724
|
+
// This avoids a second glob expansion and is safe when there are no test files.
|
|
1725
|
+
const bizCoverages = syntheticRules.map((rule) => {
|
|
1726
|
+
const kwsLower = rule.keywords.map((k) => k.toLowerCase());
|
|
1727
|
+
const matchedDescs = [];
|
|
1728
|
+
const matchedFileSet = new Set();
|
|
1729
|
+
for (const { file, descriptions } of testEntries) {
|
|
1730
|
+
const hitting = descriptions.filter((desc) => kwsLower.length > 0 && kwsLower.some((kw) => desc.includes(kw)));
|
|
1731
|
+
if (hitting.length > 0) {
|
|
1732
|
+
matchedDescs.push(...hitting);
|
|
1733
|
+
matchedFileSet.add(file);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return {
|
|
1737
|
+
rule,
|
|
1738
|
+
covered: matchedDescs.length > 0,
|
|
1739
|
+
testFiles: [...matchedFileSet],
|
|
1740
|
+
matchedTests: matchedDescs,
|
|
1741
|
+
scenarios: [],
|
|
1742
|
+
};
|
|
1743
|
+
});
|
|
1555
1744
|
const bizReport = (0, businessCoverage_1.buildBusinessCoverageReport)(bizCoverages);
|
|
1556
1745
|
const bizResult = {
|
|
1557
1746
|
type: 'business',
|
|
1558
1747
|
totalItems: bizReport.total,
|
|
1559
1748
|
coveredItems: bizReport.covered,
|
|
1560
1749
|
coveragePercent: bizReport.percentage,
|
|
1561
|
-
details:
|
|
1750
|
+
details: {
|
|
1751
|
+
...bizReport,
|
|
1752
|
+
inferred_details: inferredRulesResult.rules.reduce((acc, r) => {
|
|
1753
|
+
acc[r.id] = {
|
|
1754
|
+
source_location: r.source_location,
|
|
1755
|
+
condition: r.condition,
|
|
1756
|
+
code_snippet: r.code_snippet,
|
|
1757
|
+
type: r.type,
|
|
1758
|
+
specificKeywords: r.specificKeywords,
|
|
1759
|
+
};
|
|
1760
|
+
return acc;
|
|
1761
|
+
}, {}),
|
|
1762
|
+
},
|
|
1562
1763
|
};
|
|
1563
1764
|
allCoverageResults.push(bizResult);
|
|
1564
1765
|
console.log(` ${bizReport.covered}/${bizReport.total} inferred business rules have test coverage (${bizReport.percentage}%)`);
|
|
@@ -1621,8 +1822,69 @@ program
|
|
|
1621
1822
|
if (allCoverageResults.length > 0) {
|
|
1622
1823
|
const observabilityInfo = (0, observability_1.buildObservabilityInfo)(metricsPort);
|
|
1623
1824
|
(0, reporting_1.generateMultiFormatReports)(allCoverageResults, ['json'], reportsDir, {}, observabilityInfo);
|
|
1825
|
+
// Append discoveryInfo to coverage-summary.json for the dashboard
|
|
1826
|
+
const summaryPath = path.join(reportsDir, 'coverage-summary.json');
|
|
1827
|
+
try {
|
|
1828
|
+
const summaryJson = JSON.parse(fsMod.readFileSync(summaryPath, 'utf-8'));
|
|
1829
|
+
summaryJson.discoveryInfo = {
|
|
1830
|
+
projectRoot: rootDir,
|
|
1831
|
+
analyzedAt: new Date().toISOString(),
|
|
1832
|
+
languages: artifacts.languages,
|
|
1833
|
+
frameworks: artifacts.frameworks,
|
|
1834
|
+
serviceFilesCount: artifacts.serviceFiles.length,
|
|
1835
|
+
testFilesCount: artifacts.testFiles.length,
|
|
1836
|
+
specFilesCount: artifacts.specs.length,
|
|
1837
|
+
analysisMode: artifacts.specs.length > 0 ? 'explicit-spec' : 'inferred',
|
|
1838
|
+
};
|
|
1839
|
+
fsMod.writeFileSync(summaryPath, JSON.stringify(summaryJson, null, 2), 'utf-8');
|
|
1840
|
+
}
|
|
1841
|
+
catch {
|
|
1842
|
+
// Non-fatal — discovery info is also in scan-manifest.json
|
|
1843
|
+
}
|
|
1624
1844
|
console.log(`\nReports written to: ${reportsDir}`);
|
|
1625
1845
|
}
|
|
1846
|
+
// ── 4f. Write scan manifest ────────────────────────────────────────────
|
|
1847
|
+
try {
|
|
1848
|
+
const scanTypes = allCoverageResults.map((r) => ({
|
|
1849
|
+
type: r.type,
|
|
1850
|
+
source: artifacts.specs.length > 0 ? 'explicit' : 'inferred',
|
|
1851
|
+
itemsFound: r.totalItems,
|
|
1852
|
+
itemsCovered: r.coveredItems,
|
|
1853
|
+
coveragePercent: r.coveragePercent,
|
|
1854
|
+
}));
|
|
1855
|
+
// Add skipped types (exclude 'business' and 'integration' since these are always attempted
|
|
1856
|
+
// via rule/flow inference regardless of whether a spec file is present; their absence from
|
|
1857
|
+
// allCoverageResults means no rules or flows were discovered, which is informative on its own.)
|
|
1858
|
+
const coveredTypes = new Set(allCoverageResults.map((r) => r.type));
|
|
1859
|
+
for (const skippedType of summaryTypes_1.KNOWN_METRIC_TYPES.filter((t) => t !== 'business' && t !== 'integration')) {
|
|
1860
|
+
if (!coveredTypes.has(skippedType)) {
|
|
1861
|
+
scanTypes.push({
|
|
1862
|
+
type: skippedType,
|
|
1863
|
+
source: 'skipped',
|
|
1864
|
+
reason: artifacts.specs.length === 0 ? 'No API spec and no routes detected' : 'No data available',
|
|
1865
|
+
itemsFound: 0,
|
|
1866
|
+
itemsCovered: 0,
|
|
1867
|
+
coveragePercent: 0,
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
const manifestPath = (0, scanManifest_1.writeScanManifest)({
|
|
1872
|
+
projectRoot: rootDir,
|
|
1873
|
+
analyzedAt: new Date().toISOString(),
|
|
1874
|
+
discoveredFiles: {
|
|
1875
|
+
serviceFiles: artifacts.serviceFiles,
|
|
1876
|
+
testFiles: artifacts.testFiles,
|
|
1877
|
+
specFiles: artifacts.specs,
|
|
1878
|
+
},
|
|
1879
|
+
languages: artifacts.languages,
|
|
1880
|
+
frameworks: artifacts.frameworks,
|
|
1881
|
+
scanTypes,
|
|
1882
|
+
}, reportsDir);
|
|
1883
|
+
console.log(`Scan manifest written to: ${manifestPath}`);
|
|
1884
|
+
}
|
|
1885
|
+
catch (err) {
|
|
1886
|
+
warnings.push(`Scan manifest write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1887
|
+
}
|
|
1626
1888
|
// ── 5. Emit warnings ───────────────────────────────────────────────────
|
|
1627
1889
|
for (const w of warnings) {
|
|
1628
1890
|
console.warn(`[WARN] ${w}`);
|
|
@@ -34,6 +34,8 @@ export interface InferredBusinessRule {
|
|
|
34
34
|
source_location: string;
|
|
35
35
|
/** Raw matched code snippet */
|
|
36
36
|
code_snippet: string;
|
|
37
|
+
/** Most specific identifiable terms from the condition, for accurate test matching */
|
|
38
|
+
specificKeywords: string[];
|
|
37
39
|
}
|
|
38
40
|
export interface BusinessRuleInferenceResult {
|
|
39
41
|
rules: InferredBusinessRule[];
|
|
@@ -60,4 +62,10 @@ export declare function inferBusinessRules(serviceFiles: string[], warnings?: st
|
|
|
60
62
|
* Returns the path of the written file.
|
|
61
63
|
*/
|
|
62
64
|
export declare function writeInferredBusinessRules(result: BusinessRuleInferenceResult, reportsDir: string): string;
|
|
65
|
+
export declare const KEYWORD_STOP_WORDS: Set<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Extract the most specific identifiable terms from a rule condition string.
|
|
68
|
+
* Prioritises quoted field names and message fragments over generic identifiers.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractSpecificKeywords(condition: string): string[];
|
|
63
71
|
//# sourceMappingURL=businessRuleInference.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"businessRuleInference.d.ts","sourceRoot":"","sources":["../../../src/inference/businessRuleInference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AACjD,MAAM,MAAM,QAAQ,GAChB,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,YAAY,CAAC;AAEjB,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"businessRuleInference.d.ts","sourceRoot":"","sources":["../../../src/inference/businessRuleInference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AACjD,MAAM,MAAM,QAAQ,GAChB,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,YAAY,CAAC;AAEjB,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA2ID;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,EAAE,CA4C3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EAAE,EACtB,QAAQ,GAAE,MAAM,EAAO,GACtB,2BAA2B,CAuB7B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,2BAA2B,EACnC,UAAU,EAAE,MAAM,GACjB,MAAM,CAYR;AAID,eAAO,MAAM,kBAAkB,aAM7B,CAAC;AAEH;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwCnE"}
|
|
@@ -50,9 +50,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
50
50
|
};
|
|
51
51
|
})();
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.KEYWORD_STOP_WORDS = void 0;
|
|
53
54
|
exports.inferRulesFromFile = inferRulesFromFile;
|
|
54
55
|
exports.inferBusinessRules = inferBusinessRules;
|
|
55
56
|
exports.writeInferredBusinessRules = writeInferredBusinessRules;
|
|
57
|
+
exports.extractSpecificKeywords = extractSpecificKeywords;
|
|
56
58
|
const fs = __importStar(require("fs"));
|
|
57
59
|
const path = __importStar(require("path"));
|
|
58
60
|
const INFERENCE_PATTERNS = [
|
|
@@ -208,6 +210,7 @@ function inferRulesFromFile(filePath) {
|
|
|
208
210
|
expected_behavior: ip.behaviorTemplate(match),
|
|
209
211
|
source_location: sourceLocation,
|
|
210
212
|
code_snippet: line.trim().slice(0, 200),
|
|
213
|
+
specificKeywords: extractSpecificKeywords(condition),
|
|
211
214
|
});
|
|
212
215
|
}
|
|
213
216
|
}
|
|
@@ -258,6 +261,55 @@ function writeInferredBusinessRules(result, reportsDir) {
|
|
|
258
261
|
return outputPath;
|
|
259
262
|
}
|
|
260
263
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
264
|
+
exports.KEYWORD_STOP_WORDS = new Set([
|
|
265
|
+
'http', 'exception', 'error', 'errors', 'throw', 'throws', 'raise', 'raises',
|
|
266
|
+
'new', 'return', 'returns', 'status', 'response', 'request', 'abort',
|
|
267
|
+
'the', 'and', 'for', 'with', 'that', 'this', 'from', 'not', 'has',
|
|
268
|
+
'can', 'cant', 'be', 'been', 'must', 'will', 'was', 'are', 'have',
|
|
269
|
+
'its', 'too', 'also', 'just', 'only', 'than', 'then', 'when',
|
|
270
|
+
]);
|
|
271
|
+
/**
|
|
272
|
+
* Extract the most specific identifiable terms from a rule condition string.
|
|
273
|
+
* Prioritises quoted field names and message fragments over generic identifiers.
|
|
274
|
+
*/
|
|
275
|
+
function extractSpecificKeywords(condition) {
|
|
276
|
+
var _a, _b, _c;
|
|
277
|
+
const kwSet = new Set();
|
|
278
|
+
// 1. Extract contents of quoted strings (field names, messages)
|
|
279
|
+
// Minimum length of 2 prevents single-character tokens like punctuation or abbreviations
|
|
280
|
+
// from polluting the keyword set (e.g. single-char matches from `{ e: [...] }`).
|
|
281
|
+
const quotedMatches = (_a = condition.match(/['"]([^'"]{2,})['"]/g)) !== null && _a !== void 0 ? _a : [];
|
|
282
|
+
for (const q of quotedMatches) {
|
|
283
|
+
const inner = q.slice(1, -1);
|
|
284
|
+
// Split on common separators and add each non-trivial token
|
|
285
|
+
inner.toLowerCase().split(/[\s\-_.,!?:;/\\]+/).forEach((tok) => {
|
|
286
|
+
if (tok.length >= 2 && !exports.KEYWORD_STOP_WORDS.has(tok) && /[a-z]/.test(tok)) {
|
|
287
|
+
kwSet.add(tok);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
// 2. Extract object key identifiers from patterns like { fieldName: [...] }
|
|
292
|
+
const objKeyMatches = (_b = condition.match(/\{\s*(?:'([^']+)'|"([^"]+)"|(\w+))\s*:/g)) !== null && _b !== void 0 ? _b : [];
|
|
293
|
+
for (const m of objKeyMatches) {
|
|
294
|
+
const inner = m.replace(/^\{\s*/, '').replace(/\s*:$/, '').replace(/['"]/g, '').toLowerCase();
|
|
295
|
+
if (inner.length >= 2 && !exports.KEYWORD_STOP_WORDS.has(inner)) {
|
|
296
|
+
kwSet.add(inner);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// 3. Camel-case parts of exception / class names (e.g. "HttpException" → "http")
|
|
300
|
+
// but only non-stop identifiers of reasonable length
|
|
301
|
+
const identifiers = (_c = condition.match(/\b[A-Za-z][A-Za-z0-9]{2,}\b/g)) !== null && _c !== void 0 ? _c : [];
|
|
302
|
+
for (const id of identifiers) {
|
|
303
|
+
// Split camelCase into parts
|
|
304
|
+
const parts = id.replace(/([A-Z])/g, ' $1').toLowerCase().trim().split(/\s+/);
|
|
305
|
+
for (const part of parts) {
|
|
306
|
+
if (part.length >= 3 && !exports.KEYWORD_STOP_WORDS.has(part)) {
|
|
307
|
+
kwSet.add(part);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return [...kwSet];
|
|
312
|
+
}
|
|
261
313
|
function toSnakeCase(str) {
|
|
262
314
|
return str
|
|
263
315
|
.replace(/([A-Z])/g, '_$1')
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Inference Engine
|
|
3
|
+
*
|
|
4
|
+
* Discovers HTTP routes from Express/Koa/Hapi/Fastify source files when no
|
|
5
|
+
* OpenAPI spec is available, enabling endpoint coverage analysis without
|
|
6
|
+
* a pre-authored specification.
|
|
7
|
+
*
|
|
8
|
+
* Patterns supported:
|
|
9
|
+
* - Express/Koa: router.get('/path', ...) / app.post('/path', ...)
|
|
10
|
+
* - Multi-line: router.get(\n '/path', ...) — path on next line
|
|
11
|
+
* - Chained: router.route('/path').get(...).post(...)
|
|
12
|
+
* - JSDoc route annotations: @route {GET} /path (used only when no code pattern found)
|
|
13
|
+
*
|
|
14
|
+
* Deduplication:
|
|
15
|
+
* - Routes are deduplicated by method:path within each file.
|
|
16
|
+
* - Actual code patterns take priority over JSDoc annotations.
|
|
17
|
+
*/
|
|
18
|
+
export declare const HTTP_METHODS: readonly ["get", "post", "put", "patch", "delete", "head", "options"];
|
|
19
|
+
export type HttpMethod = typeof HTTP_METHODS[number];
|
|
20
|
+
export interface InferredRoute {
|
|
21
|
+
method: HttpMethod;
|
|
22
|
+
path: string;
|
|
23
|
+
/** Primary service function called in the route handler, if detectable */
|
|
24
|
+
handlerFunction?: string;
|
|
25
|
+
sourceFile: string;
|
|
26
|
+
lineNumber: number;
|
|
27
|
+
/** How this route was discovered */
|
|
28
|
+
discoveredVia: 'code' | 'jsdoc';
|
|
29
|
+
}
|
|
30
|
+
export interface RouteInferenceResult {
|
|
31
|
+
routes: InferredRoute[];
|
|
32
|
+
filesAnalyzed: number;
|
|
33
|
+
warnings: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Infer routes from a single source file.
|
|
37
|
+
* Routes are deduplicated by method:path within the file.
|
|
38
|
+
* Code-based patterns take priority over JSDoc annotations for the same method+path.
|
|
39
|
+
*/
|
|
40
|
+
export declare function inferRoutesFromFile(filePath: string): InferredRoute[];
|
|
41
|
+
/**
|
|
42
|
+
* Infer routes from a set of service source files.
|
|
43
|
+
*/
|
|
44
|
+
export declare function inferRoutes(serviceFiles: string[]): RouteInferenceResult;
|
|
45
|
+
/**
|
|
46
|
+
* Write inferred routes to the reports directory.
|
|
47
|
+
* Returns the path of the written file.
|
|
48
|
+
*/
|
|
49
|
+
export declare function writeInferredRoutes(result: RouteInferenceResult, reportsDir: string): string;
|
|
50
|
+
//# sourceMappingURL=routeInference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeInference.d.ts","sourceRoot":"","sources":["../../../src/inference/routeInference.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,eAAO,MAAM,YAAY,uEAAwE,CAAC;AAClG,MAAM,MAAM,UAAU,GAAG,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAoDD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAiFrE;AAiBD;;GAEG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAgBxE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAY5F"}
|