1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const fs = require('fs'); 17const sourceMap = require('source-map'); 18const path = require('path'); 19 20const PROJECT_ROOT = path.join(__dirname, '..', '..'); 21const COVERAGE_DIR = path.join(PROJECT_ROOT, 'coverage'); 22const COVERAGE_FILE = path.join(COVERAGE_DIR, 'coverage.json'); 23const NEW_COVERAGE_FILE = path.join(COVERAGE_DIR, 'newCoverage.json'); 24 25/** 26 * Processes statement map data using source map consumer 27 * @param {Object} statementMap - Statement map data 28 * @param {Object} consumer - Source map consumer 29 */ 30function processStatementMap(statementMap, consumer) { 31 for (const id in statementMap) { 32 const statement = statementMap[id]; 33 const startPos = consumer.originalPositionFor(statement.start); 34 const endPos = consumer.originalPositionFor(statement.end); 35 36 statement.start = { line: startPos.line, column: startPos.column }; 37 statement.end = { line: endPos.line, column: endPos.column }; 38 } 39} 40 41/** 42 * Processes function map data using source map consumer 43 * @param {Object} functionMap - Function map data 44 * @param {Object} consumer - Source map consumer 45 */ 46function processFunctionMap(functionMap, consumer) { 47 for (const id in functionMap) { 48 const func = functionMap[id]; 49 50 const declStart = consumer.originalPositionFor(func.decl.start); 51 const declEnd = consumer.originalPositionFor(func.decl.end); 52 const locStart = consumer.originalPositionFor(func.loc.start); 53 const locEnd = consumer.originalPositionFor(func.loc.end); 54 55 func.decl = { 56 start: { line: declStart.line, column: declStart.column }, 57 end: { line: declEnd.line, column: declEnd.column } 58 }; 59 60 func.loc = { 61 start: { line: locStart.line, column: locStart.column }, 62 end: { line: locEnd.line, column: locEnd.column } 63 }; 64 65 func.line = declStart.line; 66 } 67} 68 69/** 70 * Processes branch map data using source map consumer 71 * @param {Object} branchMap - Branch map data 72 * @param {Object} consumer - Source map consumer 73 */ 74function processBranchMap(branchMap, consumer) { 75 for (const id in branchMap) { 76 const branch = branchMap[id]; 77 78 // Process locations 79 branch.locations.forEach(location => { 80 const startPos = consumer.originalPositionFor(location.start); 81 const endPos = consumer.originalPositionFor(location.end); 82 83 location.start = { line: startPos.line, column: startPos.column }; 84 location.end = { line: endPos.line, column: endPos.column }; 85 }); 86 87 // Process loc 88 const locStart = consumer.originalPositionFor(branch.loc.start); 89 const locEnd = consumer.originalPositionFor(branch.loc.end); 90 91 branch.loc = { 92 start: { line: locStart.line, column: locStart.column }, 93 end: { line: locEnd.line, column: locEnd.column } 94 }; 95 96 branch.line = locStart.line; 97 } 98} 99 100/** 101 * Collects and processes coverage data using source maps 102 */ 103async function collectCoverage() { 104 if (!fs.existsSync(COVERAGE_FILE)) { 105 throw new Error(`Coverage file not found: ${COVERAGE_FILE}`); 106 } 107 108 const coverageData = JSON.parse(fs.readFileSync(COVERAGE_FILE, 'utf8')); 109 const newCoverageData = {}; 110 111 for (const file in coverageData) { 112 const mapFile = `${file}.map`; 113 114 if (!fs.existsSync(mapFile)) { 115 console.warn(`Source map not found for: ${file}`); 116 continue; 117 } 118 119 const sourceMapData = JSON.parse(fs.readFileSync(mapFile, 'utf8')); 120 const sources = sourceMapData.sources; 121 const newFile = path.join(path.dirname(mapFile), sources[0]); 122 123 await sourceMap.SourceMapConsumer.with(sourceMapData, null, (consumer) => { 124 const fileCoverage = { ...coverageData[file] }; 125 fileCoverage.path = newFile; 126 127 processStatementMap(fileCoverage.statementMap, consumer); 128 processFunctionMap(fileCoverage.functionMap, consumer); 129 processBranchMap(fileCoverage.branchMap, consumer); 130 131 newCoverageData[newFile] = fileCoverage; 132 }); 133 } 134 135 fs.writeFileSync( 136 NEW_COVERAGE_FILE, 137 JSON.stringify(newCoverageData, null, 4) 138 ); 139} 140 141// Execute and handle errors 142collectCoverage() 143 .then(() => console.log('Coverage collection completed successfully')) 144 .catch(error => { 145 console.error('Error collecting coverage:', error); 146 process.exit(1); 147 });