• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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