source: trip-planner-front/node_modules/istanbul-reports/lib/html/annotator.js@ ceaed42

Last change on this file since ceaed42 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*
2 Copyright 2012-2015, Yahoo Inc.
3 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
4 */
5'use strict';
6
7const InsertionText = require('./insertion-text');
8const lt = '\u0001';
9const gt = '\u0002';
10const RE_LT = /</g;
11const RE_GT = />/g;
12const RE_AMP = /&/g;
13// eslint-disable-next-line
14var RE_lt = /\u0001/g;
15// eslint-disable-next-line
16var RE_gt = /\u0002/g;
17
18function title(str) {
19 return ' title="' + str + '" ';
20}
21
22function customEscape(text) {
23 text = String(text);
24 return text
25 .replace(RE_AMP, '&amp;')
26 .replace(RE_LT, '&lt;')
27 .replace(RE_GT, '&gt;')
28 .replace(RE_lt, '<')
29 .replace(RE_gt, '>');
30}
31
32function annotateLines(fileCoverage, structuredText) {
33 const lineStats = fileCoverage.getLineCoverage();
34 if (!lineStats) {
35 return;
36 }
37 Object.entries(lineStats).forEach(([lineNumber, count]) => {
38 if (structuredText[lineNumber]) {
39 structuredText[lineNumber].covered = count > 0 ? 'yes' : 'no';
40 structuredText[lineNumber].hits = count;
41 }
42 });
43}
44
45function annotateStatements(fileCoverage, structuredText) {
46 const statementStats = fileCoverage.s;
47 const statementMeta = fileCoverage.statementMap;
48 Object.entries(statementStats).forEach(([stName, count]) => {
49 const meta = statementMeta[stName];
50 const type = count > 0 ? 'yes' : 'no';
51 const startCol = meta.start.column;
52 let endCol = meta.end.column + 1;
53 const startLine = meta.start.line;
54 const endLine = meta.end.line;
55 const openSpan =
56 lt +
57 'span class="' +
58 (meta.skip ? 'cstat-skip' : 'cstat-no') +
59 '"' +
60 title('statement not covered') +
61 gt;
62 const closeSpan = lt + '/span' + gt;
63 let text;
64
65 if (type === 'no' && structuredText[startLine]) {
66 if (endLine !== startLine) {
67 endCol = structuredText[startLine].text.originalLength();
68 }
69 text = structuredText[startLine].text;
70 text.wrap(
71 startCol,
72 openSpan,
73 startCol < endCol ? endCol : text.originalLength(),
74 closeSpan
75 );
76 }
77 });
78}
79
80function annotateFunctions(fileCoverage, structuredText) {
81 const fnStats = fileCoverage.f;
82 const fnMeta = fileCoverage.fnMap;
83 if (!fnStats) {
84 return;
85 }
86 Object.entries(fnStats).forEach(([fName, count]) => {
87 const meta = fnMeta[fName];
88 const type = count > 0 ? 'yes' : 'no';
89 const startCol = meta.decl.start.column;
90 let endCol = meta.decl.end.column + 1;
91 const startLine = meta.decl.start.line;
92 const endLine = meta.decl.end.line;
93 const openSpan =
94 lt +
95 'span class="' +
96 (meta.skip ? 'fstat-skip' : 'fstat-no') +
97 '"' +
98 title('function not covered') +
99 gt;
100 const closeSpan = lt + '/span' + gt;
101 let text;
102
103 if (type === 'no' && structuredText[startLine]) {
104 if (endLine !== startLine) {
105 endCol = structuredText[startLine].text.originalLength();
106 }
107 text = structuredText[startLine].text;
108 text.wrap(
109 startCol,
110 openSpan,
111 startCol < endCol ? endCol : text.originalLength(),
112 closeSpan
113 );
114 }
115 });
116}
117
118function annotateBranches(fileCoverage, structuredText) {
119 const branchStats = fileCoverage.b;
120 const branchMeta = fileCoverage.branchMap;
121 if (!branchStats) {
122 return;
123 }
124
125 Object.entries(branchStats).forEach(([branchName, branchArray]) => {
126 const sumCount = branchArray.reduce((p, n) => p + n, 0);
127 const metaArray = branchMeta[branchName].locations;
128 let i;
129 let count;
130 let meta;
131 let startCol;
132 let endCol;
133 let startLine;
134 let endLine;
135 let openSpan;
136 let closeSpan;
137 let text;
138
139 // only highlight if partial branches are missing or if there is a
140 // single uncovered branch.
141 if (sumCount > 0 || (sumCount === 0 && branchArray.length === 1)) {
142 for (
143 i = 0;
144 i < branchArray.length && i < metaArray.length;
145 i += 1
146 ) {
147 count = branchArray[i];
148 meta = metaArray[i];
149 startCol = meta.start.column;
150 endCol = meta.end.column + 1;
151 startLine = meta.start.line;
152 endLine = meta.end.line;
153 openSpan =
154 lt +
155 'span class="branch-' +
156 i +
157 ' ' +
158 (meta.skip ? 'cbranch-skip' : 'cbranch-no') +
159 '"' +
160 title('branch not covered') +
161 gt;
162 closeSpan = lt + '/span' + gt;
163
164 if (count === 0 && structuredText[startLine]) {
165 //skip branches taken
166 if (endLine !== startLine) {
167 endCol = structuredText[
168 startLine
169 ].text.originalLength();
170 }
171 text = structuredText[startLine].text;
172 if (branchMeta[branchName].type === 'if') {
173 // 'if' is a special case
174 // since the else branch might not be visible, being non-existent
175 text.insertAt(
176 startCol,
177 lt +
178 'span class="' +
179 (meta.skip
180 ? 'skip-if-branch'
181 : 'missing-if-branch') +
182 '"' +
183 title(
184 (i === 0 ? 'if' : 'else') +
185 ' path not taken'
186 ) +
187 gt +
188 (i === 0 ? 'I' : 'E') +
189 lt +
190 '/span' +
191 gt,
192 true,
193 false
194 );
195 } else {
196 text.wrap(
197 startCol,
198 openSpan,
199 startCol < endCol ? endCol : text.originalLength(),
200 closeSpan
201 );
202 }
203 }
204 }
205 }
206 });
207}
208
209function annotateSourceCode(fileCoverage, sourceStore) {
210 let codeArray;
211 let lineCoverageArray;
212 try {
213 const sourceText = sourceStore.getSource(fileCoverage.path);
214 const code = sourceText.split(/(?:\r?\n)|\r/);
215 let count = 0;
216 const structured = code.map(str => {
217 count += 1;
218 return {
219 line: count,
220 covered: 'neutral',
221 hits: 0,
222 text: new InsertionText(str, true)
223 };
224 });
225 structured.unshift({
226 line: 0,
227 covered: null,
228 text: new InsertionText('')
229 });
230 annotateLines(fileCoverage, structured);
231 //note: order is important, since statements typically result in spanning the whole line and doing branches late
232 //causes mismatched tags
233 annotateBranches(fileCoverage, structured);
234 annotateFunctions(fileCoverage, structured);
235 annotateStatements(fileCoverage, structured);
236 structured.shift();
237
238 codeArray = structured.map(
239 item => customEscape(item.text.toString()) || '&nbsp;'
240 );
241
242 lineCoverageArray = structured.map(item => ({
243 covered: item.covered,
244 hits: item.hits > 0 ? item.hits + 'x' : '&nbsp;'
245 }));
246
247 return {
248 annotatedCode: codeArray,
249 lineCoverage: lineCoverageArray,
250 maxLines: structured.length
251 };
252 } catch (ex) {
253 codeArray = [ex.message];
254 lineCoverageArray = [{ covered: 'no', hits: 0 }];
255 String(ex.stack || '')
256 .split(/\r?\n/)
257 .forEach(line => {
258 codeArray.push(line);
259 lineCoverageArray.push({ covered: 'no', hits: 0 });
260 });
261 return {
262 annotatedCode: codeArray,
263 lineCoverage: lineCoverageArray,
264 maxLines: codeArray.length
265 };
266 }
267}
268
269module.exports = annotateSourceCode;
Note: See TracBrowser for help on using the repository browser.