mirror of
				https://gitea.com/actions/setup-python.git
				synced 2025-11-01 01:28:08 +07:00 
			
		
		
		
	
		
			
				
	
	
		
			276 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			276 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  Copyright 2012-2015, Yahoo Inc.
 | |
|  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 | |
|  */
 | |
| 'use strict';
 | |
| 
 | |
| const InsertionText = require('./insertion-text');
 | |
| const lt = '\u0001';
 | |
| const gt = '\u0002';
 | |
| const RE_LT = /</g;
 | |
| const RE_GT = />/g;
 | |
| const RE_AMP = /&/g;
 | |
| // eslint-disable-next-line
 | |
| var RE_lt = /\u0001/g;
 | |
| // eslint-disable-next-line
 | |
| var RE_gt = /\u0002/g;
 | |
| 
 | |
| function title(str) {
 | |
|     return ' title="' + str + '" ';
 | |
| }
 | |
| 
 | |
| function customEscape(text) {
 | |
|     text = String(text);
 | |
|     return text
 | |
|         .replace(RE_AMP, '&')
 | |
|         .replace(RE_LT, '<')
 | |
|         .replace(RE_GT, '>')
 | |
|         .replace(RE_lt, '<')
 | |
|         .replace(RE_gt, '>');
 | |
| }
 | |
| 
 | |
| function annotateLines(fileCoverage, structuredText) {
 | |
|     const lineStats = fileCoverage.getLineCoverage();
 | |
|     if (!lineStats) {
 | |
|         return;
 | |
|     }
 | |
|     Object.keys(lineStats).forEach(lineNumber => {
 | |
|         const count = lineStats[lineNumber];
 | |
|         if (structuredText[lineNumber]) {
 | |
|             structuredText[lineNumber].covered = count > 0 ? 'yes' : 'no';
 | |
|             structuredText[lineNumber].hits = count;
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function annotateStatements(fileCoverage, structuredText) {
 | |
|     const statementStats = fileCoverage.s;
 | |
|     const statementMeta = fileCoverage.statementMap;
 | |
|     Object.keys(statementStats).forEach(stName => {
 | |
|         const count = statementStats[stName];
 | |
|         const meta = statementMeta[stName];
 | |
|         const type = count > 0 ? 'yes' : 'no';
 | |
|         const startCol = meta.start.column;
 | |
|         let endCol = meta.end.column + 1;
 | |
|         const startLine = meta.start.line;
 | |
|         const endLine = meta.end.line;
 | |
|         const openSpan =
 | |
|             lt +
 | |
|             'span class="' +
 | |
|             (meta.skip ? 'cstat-skip' : 'cstat-no') +
 | |
|             '"' +
 | |
|             title('statement not covered') +
 | |
|             gt;
 | |
|         const closeSpan = lt + '/span' + gt;
 | |
|         let text;
 | |
| 
 | |
|         if (type === 'no' && structuredText[startLine]) {
 | |
|             if (endLine !== startLine) {
 | |
|                 endCol = structuredText[startLine].text.originalLength();
 | |
|             }
 | |
|             text = structuredText[startLine].text;
 | |
|             text.wrap(
 | |
|                 startCol,
 | |
|                 openSpan,
 | |
|                 startCol < endCol ? endCol : text.originalLength(),
 | |
|                 closeSpan
 | |
|             );
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function annotateFunctions(fileCoverage, structuredText) {
 | |
|     const fnStats = fileCoverage.f;
 | |
|     const fnMeta = fileCoverage.fnMap;
 | |
|     if (!fnStats) {
 | |
|         return;
 | |
|     }
 | |
|     Object.keys(fnStats).forEach(fName => {
 | |
|         const count = fnStats[fName];
 | |
|         const meta = fnMeta[fName];
 | |
|         const type = count > 0 ? 'yes' : 'no';
 | |
|         const startCol = meta.decl.start.column;
 | |
|         let endCol = meta.decl.end.column + 1;
 | |
|         const startLine = meta.decl.start.line;
 | |
|         const endLine = meta.decl.end.line;
 | |
|         const openSpan =
 | |
|             lt +
 | |
|             'span class="' +
 | |
|             (meta.skip ? 'fstat-skip' : 'fstat-no') +
 | |
|             '"' +
 | |
|             title('function not covered') +
 | |
|             gt;
 | |
|         const closeSpan = lt + '/span' + gt;
 | |
|         let text;
 | |
| 
 | |
|         if (type === 'no' && structuredText[startLine]) {
 | |
|             if (endLine !== startLine) {
 | |
|                 endCol = structuredText[startLine].text.originalLength();
 | |
|             }
 | |
|             text = structuredText[startLine].text;
 | |
|             text.wrap(
 | |
|                 startCol,
 | |
|                 openSpan,
 | |
|                 startCol < endCol ? endCol : text.originalLength(),
 | |
|                 closeSpan
 | |
|             );
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function annotateBranches(fileCoverage, structuredText) {
 | |
|     const branchStats = fileCoverage.b;
 | |
|     const branchMeta = fileCoverage.branchMap;
 | |
|     if (!branchStats) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     Object.keys(branchStats).forEach(branchName => {
 | |
|         const branchArray = branchStats[branchName];
 | |
|         const sumCount = branchArray.reduce((p, n) => p + n, 0);
 | |
|         const metaArray = branchMeta[branchName].locations;
 | |
|         let i;
 | |
|         let count;
 | |
|         let meta;
 | |
|         let startCol;
 | |
|         let endCol;
 | |
|         let startLine;
 | |
|         let endLine;
 | |
|         let openSpan;
 | |
|         let closeSpan;
 | |
|         let text;
 | |
| 
 | |
|         // only highlight if partial branches are missing or if there is a
 | |
|         // single uncovered branch.
 | |
|         if (sumCount > 0 || (sumCount === 0 && branchArray.length === 1)) {
 | |
|             for (
 | |
|                 i = 0;
 | |
|                 i < branchArray.length && i < metaArray.length;
 | |
|                 i += 1
 | |
|             ) {
 | |
|                 count = branchArray[i];
 | |
|                 meta = metaArray[i];
 | |
|                 startCol = meta.start.column;
 | |
|                 endCol = meta.end.column + 1;
 | |
|                 startLine = meta.start.line;
 | |
|                 endLine = meta.end.line;
 | |
|                 openSpan =
 | |
|                     lt +
 | |
|                     'span class="branch-' +
 | |
|                     i +
 | |
|                     ' ' +
 | |
|                     (meta.skip ? 'cbranch-skip' : 'cbranch-no') +
 | |
|                     '"' +
 | |
|                     title('branch not covered') +
 | |
|                     gt;
 | |
|                 closeSpan = lt + '/span' + gt;
 | |
| 
 | |
|                 if (count === 0 && structuredText[startLine]) {
 | |
|                     //skip branches taken
 | |
|                     if (endLine !== startLine) {
 | |
|                         endCol = structuredText[
 | |
|                             startLine
 | |
|                         ].text.originalLength();
 | |
|                     }
 | |
|                     text = structuredText[startLine].text;
 | |
|                     if (branchMeta[branchName].type === 'if') {
 | |
|                         // 'if' is a special case
 | |
|                         // since the else branch might not be visible, being non-existent
 | |
|                         text.insertAt(
 | |
|                             startCol,
 | |
|                             lt +
 | |
|                                 'span class="' +
 | |
|                                 (meta.skip
 | |
|                                     ? 'skip-if-branch'
 | |
|                                     : 'missing-if-branch') +
 | |
|                                 '"' +
 | |
|                                 title(
 | |
|                                     (i === 0 ? 'if' : 'else') +
 | |
|                                         ' path not taken'
 | |
|                                 ) +
 | |
|                                 gt +
 | |
|                                 (i === 0 ? 'I' : 'E') +
 | |
|                                 lt +
 | |
|                                 '/span' +
 | |
|                                 gt,
 | |
|                             true,
 | |
|                             false
 | |
|                         );
 | |
|                     } else {
 | |
|                         text.wrap(
 | |
|                             startCol,
 | |
|                             openSpan,
 | |
|                             startCol < endCol ? endCol : text.originalLength(),
 | |
|                             closeSpan
 | |
|                         );
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     });
 | |
| }
 | |
| 
 | |
| function annotateSourceCode(fileCoverage, sourceStore) {
 | |
|     let codeArray;
 | |
|     let lineCoverageArray;
 | |
|     try {
 | |
|         const sourceText = sourceStore.getSource(fileCoverage.path);
 | |
|         const code = sourceText.split(/(?:\r?\n)|\r/);
 | |
|         let count = 0;
 | |
|         const structured = code.map(str => {
 | |
|             count += 1;
 | |
|             return {
 | |
|                 line: count,
 | |
|                 covered: 'neutral',
 | |
|                 hits: 0,
 | |
|                 text: new InsertionText(str, true)
 | |
|             };
 | |
|         });
 | |
|         structured.unshift({
 | |
|             line: 0,
 | |
|             covered: null,
 | |
|             text: new InsertionText('')
 | |
|         });
 | |
|         annotateLines(fileCoverage, structured);
 | |
|         //note: order is important, since statements typically result in spanning the whole line and doing branches late
 | |
|         //causes mismatched tags
 | |
|         annotateBranches(fileCoverage, structured);
 | |
|         annotateFunctions(fileCoverage, structured);
 | |
|         annotateStatements(fileCoverage, structured);
 | |
|         structured.shift();
 | |
| 
 | |
|         codeArray = structured.map(
 | |
|             item => customEscape(item.text.toString()) || ' '
 | |
|         );
 | |
| 
 | |
|         lineCoverageArray = structured.map(item => ({
 | |
|             covered: item.covered,
 | |
|             hits: item.hits > 0 ? item.hits + 'x' : ' '
 | |
|         }));
 | |
| 
 | |
|         return {
 | |
|             annotatedCode: codeArray,
 | |
|             lineCoverage: lineCoverageArray,
 | |
|             maxLines: structured.length
 | |
|         };
 | |
|     } catch (ex) {
 | |
|         codeArray = [ex.message];
 | |
|         lineCoverageArray = [{ covered: 'no', hits: 0 }];
 | |
|         String(ex.stack || '')
 | |
|             .split(/\r?\n/)
 | |
|             .forEach(line => {
 | |
|                 codeArray.push(line);
 | |
|                 lineCoverageArray.push({ covered: 'no', hits: 0 });
 | |
|             });
 | |
|         return {
 | |
|             annotatedCode: codeArray,
 | |
|             lineCoverage: lineCoverageArray,
 | |
|             maxLines: codeArray.length
 | |
|         };
 | |
|     }
 | |
| }
 | |
| 
 | |
| module.exports = {
 | |
|     annotateSourceCode
 | |
| };
 |