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 16import * as path from 'path'; 17import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger'; 18import { FileReports } from '../../model/Defects'; 19import { FileUtils, WriteFileMode } from './FileUtils'; 20 21const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'GeneratingJsonFile'); 22const severitys: string[] = ['OFF', 'WARN', 'ERROR', 'SUGGESTION']; 23const FILE_NAMING_RULE = '@hw-stylistic/file-naming-convention'; 24 25export class GeneratingJsonFile { 26 public static generatingJsonFile(filePath: string, fileReports: FileReports[]): void { 27 const fileDefectInfos = this.format(fileReports); 28 let results: Map<string, FileDefectInfo> = new Map(); 29 for (let fileDefectInfo of fileDefectInfos) { 30 this.addResult(fileDefectInfo, results); 31 } 32 const jsonString = this.format2(results); 33 try { 34 FileUtils.writeToFile(filePath, jsonString, WriteFileMode.OVERWRITE); 35 } catch (error) { 36 logger.error(`write file ${filePath} failed, error: ${error}`); 37 } 38 } 39 40 /** 41 * 过滤掉部分不需要的defect属性 42 * 43 * @param fileReports 原始文件缺陷信息数组 44 * @returns 过滤后的文件缺陷信息数组 45 */ 46 private static format(fileReports: FileReports[]): FileDefectInfo[] { 47 const fileDefectInfos: FileDefectInfo[] = []; 48 for (const fileReport of fileReports) { 49 const fileDefectInfo: FileDefectInfo = { 50 filePath: fileReport.filePath, 51 defects: [] 52 }; 53 for (const defect of fileReport.defects) { 54 const defectInfo: DefectInfo = { 55 reportLine: defect.reportLine, 56 reportColumn: defect.reportColumn, 57 ruleId: defect.ruleId, 58 severity: severitys[defect.severity], 59 mergeKey: defect.mergeKey, 60 description: defect.description, 61 ruleDocPath: defect.ruleDocPath 62 }; 63 fileDefectInfo.defects.push(defectInfo); 64 } 65 fileDefectInfos.push(fileDefectInfo); 66 } 67 return fileDefectInfos; 68 } 69 70 private static addResult(defect: FileDefectInfo, results: Map<string, FileDefectInfo>): void { 71 const normalizedPath = path.normalize(defect.filePath).toLocaleLowerCase(); 72 if (!results.has(normalizedPath)) { 73 results.set(normalizedPath, defect); 74 } else { 75 results.get(normalizedPath)?.defects.push(...defect.defects); 76 } 77 const defectInfo = results.get(normalizedPath); 78 defectInfo?.defects.sort((defectA, defectB) => { 79 if (defectA.ruleId === FILE_NAMING_RULE) { 80 return -1; 81 } 82 if (defectB.ruleId === FILE_NAMING_RULE) { 83 return 1; 84 } 85 if (defectA.reportLine === defectB.reportLine) { 86 if (defectA.reportColumn === defectB.reportColumn) { 87 return defectA.mergeKey.localeCompare(defectB.mergeKey); 88 } 89 return defectA.reportColumn - defectB.reportColumn; 90 } 91 return defectA.reportLine - defectB.reportLine; 92 }); 93 } 94 95 private static format2(results: Map<string, FileDefectInfo>): string { 96 const jsonResults: JsonResult[] = []; 97 for (let result of results) { 98 const oneResult: JsonResult = { 99 filePath: '', 100 messages: [] 101 }; 102 oneResult.filePath = result[1].filePath; 103 let defects = result[1].defects; 104 for (let defect of defects) { 105 const oneDefect: SimpleDefect = { 106 line: 0, 107 column: 0, 108 severity: '', 109 message: '', 110 rule: '', 111 }; 112 oneDefect.line = defect.reportLine; 113 oneDefect.column = defect.reportColumn; 114 oneDefect.severity = defect.severity; 115 oneDefect.message = defect.description; 116 oneDefect.rule = defect.ruleId; 117 oneResult.messages.push(oneDefect); 118 } 119 jsonResults.push(oneResult); 120 } 121 return JSON.stringify(jsonResults, null, 2); 122 } 123} 124 125interface JsonResult { 126 filePath: string; 127 messages: SimpleDefect[]; 128} 129 130interface SimpleDefect { 131 line: number; 132 column: number; 133 severity: string; 134 message: string; 135 rule: string | null; 136} 137 138interface FileDefectInfo { 139 filePath: string; 140 defects: DefectInfo[]; 141} 142 143interface DefectInfo { 144 severity: string; 145 description: string; 146 mergeKey: string; 147 reportLine: number; 148 reportColumn: number; 149 ruleId: string | null; 150 ruleDocPath: string | null; 151} 152