1/*
2 * Copyright (c) 2022-2024 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 fs from 'fs';
17
18const ARK_TS_ISSUES_PREFIX = 'ArkTS';
19const ARK_TS_ISSUES_ERROR_CATEGORY = 'ArkTS Migration Errors';
20
21interface DefectInfo {
22  // warn: 1; error: 2;
23  severity: number;
24  description: string;
25  mergeKey: string;
26  reportLine: number;
27  reportColumn: number;
28  ruleId: string | null;
29  ruleDocPath: string | null;
30  category: string | null;
31  fixable: boolean;
32  fixKey: string;
33}
34
35interface FileDefectInfo {
36  defects: DefectInfo[];
37  output: string | undefined;
38  filePath: string;
39}
40
41type ReportJson = FileDefectInfo[];
42
43interface ArkTsIssueType {
44  description: string;
45  type: string;
46  count: number;
47}
48
49interface Statistics {
50  totalErrors: number;
51  totalWarnings: number;
52  linesWithErrors: number;
53  linesWithWarnings: number;
54  issues: Map<number, ArkTsIssueType>;
55}
56
57function isError(defectInfo: DefectInfo): boolean {
58  return defectInfo.category === ARK_TS_ISSUES_ERROR_CATEGORY;
59}
60
61function fillIssueInfo(statistics: Statistics, defectInfo: DefectInfo): void {
62  const recipeNo = parseInt(
63    defectInfo.ruleDocPath.substring('docs/recipe'.length, defectInfo.ruleDocPath.length - '.md'.length)
64  );
65  const issueInfo = statistics.issues.get(recipeNo);
66  if (!issueInfo) {
67    statistics.issues.set(recipeNo, {
68      description: defectInfo.description,
69      type: isError(defectInfo) ? 'error' : 'warn',
70      count: 1
71    });
72  } else {
73    issueInfo.count += 1;
74  }
75}
76
77function parse(reportJson: ReportJson): Statistics {
78  const statistics: Statistics = {
79    totalErrors: 0,
80    totalWarnings: 0,
81    linesWithErrors: 0,
82    linesWithWarnings: 0,
83    issues: new Map()
84  };
85
86  for (const fileInfo of reportJson) {
87    const linesWithErrors: Set<number> = new Set();
88    const linesWithWarnings: Set<number> = new Set();
89
90    for (const defectInfo of fileInfo.defects) {
91      // count only issues from ArkTS Linter
92      if (!defectInfo.category.startsWith(ARK_TS_ISSUES_PREFIX)) {
93        continue;
94      }
95
96      fillIssueInfo(statistics, defectInfo);
97
98      if (isError(defectInfo)) {
99        statistics.totalErrors += 1;
100        linesWithErrors.add(defectInfo.reportLine);
101      } else {
102        statistics.totalWarnings += 1;
103        linesWithWarnings.add(defectInfo.reportLine);
104      }
105    }
106    statistics.linesWithErrors += linesWithErrors.size;
107    statistics.linesWithWarnings += linesWithWarnings.size;
108  }
109
110  return statistics;
111}
112
113function read(filePath: string): ReportJson {
114  return JSON.parse(fs.readFileSync(filePath, { encoding: 'utf8', flag: 'r' }));
115}
116
117function main(): void {
118  if (process.argv.length < 3) {
119    console.error('Path to input json was not provided, exiting');
120    process.exit(1);
121  }
122  console.log(parse(read(process.argv[2])));
123}
124
125/*
126 * file is stored in project's directory under the following path:
127 * <PROJECT_ROOT_DIR>/.idea/code-linter/eslintAgent/output.json
128 */
129main();
130