• 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 fs from 'node:fs';
17import * as path from 'node:path';
18import type { LintRunResult } from '../../LintRunResult';
19import type { ProblemInfo } from '../../ProblemInfo';
20import * as mk from '../../utils/consts/MapKeyConst';
21import { countFiles } from './CountFile';
22import { countNapiFiles } from './CountNapiFile';
23import type { ProblemNumbersInfo } from './ProblemNumbersInfo';
24import type { ProblemStatisticsInfo } from './ProblemStatisticsInfo';
25import type { RuleDetailedErrorInfo } from './RuleDetailedErrorInfo';
26import type { StatisticsReportInPutInfo } from './StatisticsReportInPutInfo';
27import type { TimeRecorder } from './TimeRecorder';
28import { WorkLoadInfo } from './WorkLoadInfo';
29
30export function getProblemStatisticsInfo(
31  problemNumbers: ProblemNumbersInfo,
32  ruleToNumbersMap: Map<string, number>,
33  ruleToAutoFixedNumbersMap: Map<string, number>,
34  timeRecorder: TimeRecorder,
35  WorkLoadInfo?: WorkLoadInfo
36): ProblemStatisticsInfo {
37  const problemNumberMap: Map<string, number> = new Map();
38  problemNumberMap.set(mk.TOTAL_PROBLEMS, problemNumbers.totalProblemNumbers);
39  problemNumberMap.set(mk.ONE_POINT_ONE_PROBLEMS, problemNumbers.arkOnePointOneProblemNumbers);
40  problemNumberMap.set(mk.ONE_POINT_TWO_PROBLEMS, problemNumbers.arkOnePointTWOProblemNumbers);
41  problemNumberMap.set(mk.CAN_BE_AUTO_FIXED_PROBLEMS_NUMBERS, problemNumbers.canBeAutoFixedproblemNumbers);
42  problemNumberMap.set(mk.NEED_TO_NAMUAL_FIX_PROBLEM_NUMBERS, problemNumbers.needToManualFixproblemNumbers);
43
44  const scanTime = timeRecorder.getScanTime();
45  const migrationTime = timeRecorder.getMigrationTime();
46  const usedTimeMap: Map<string, string> = new Map();
47  usedTimeMap.set(mk.SCAN_TIME, scanTime);
48  usedTimeMap.set(mk.MIGRATION_TIME, migrationTime);
49
50  const detailRuleProblemsMap: Map<string, RuleDetailedErrorInfo> = new Map();
51  ruleToNumbersMap.forEach((value, key) => {
52    const ruleDetailedErrorInfo: RuleDetailedErrorInfo = {
53      rule: key,
54      problemNumbers: value,
55      canBeAutoFixedMumbers: ruleToAutoFixedNumbersMap.get(key) ?? 0
56    };
57    detailRuleProblemsMap.set(key, ruleDetailedErrorInfo);
58  });
59
60  const problemStatisticsInfo: ProblemStatisticsInfo = {
61    problems: Object.fromEntries(problemNumberMap),
62    usedTime: Object.fromEntries(usedTimeMap),
63    WorkLoadInfo: WorkLoadInfo,
64    eachRuleProblemsDetail: Array.from(detailRuleProblemsMap.values())
65  };
66  return problemStatisticsInfo;
67}
68
69export function getArktsOnePointOneProlemNumbers(problems: ProblemInfo[]): number {
70  let problemNumbersForATSOnePointOne: number = 0;
71  const signForOne: string = 's2d';
72  problems.forEach((problem) => {
73    if (problem.rule !== undefined) {
74      if (problem.rule.includes(signForOne)) {
75        problemNumbersForATSOnePointOne = problemNumbersForATSOnePointOne + 1;
76      }
77    }
78  });
79  return problemNumbersForATSOnePointOne;
80}
81
82export function accumulateRuleNumbers(
83  problems: ProblemInfo[],
84  ruleToNumbersMap: Map<string, number>,
85  ruleToAutoFixedNumbersMap: Map<string, number>
86): void {
87  problems.forEach((problem) => {
88    if (problem.rule !== undefined) {
89      if (problem.autofix) {
90        const currentNumber = ruleToAutoFixedNumbersMap.get(problem.rule) || 0;
91        ruleToAutoFixedNumbersMap.set(problem.rule, currentNumber + 1);
92      }
93      const currentNumber = ruleToNumbersMap.get(problem.rule) || 0;
94      ruleToNumbersMap.set(problem.rule, currentNumber + 1);
95    }
96  });
97}
98
99export async function generateReportFile(reportName: string, reportData, reportPath?: string): Promise<void> {
100  let reportFilePath = path.join(reportName);
101  if (reportPath !== undefined) {
102    reportFilePath = path.join(path.normalize(reportPath), reportName);
103  }
104  try {
105    await fs.promises.mkdir(path.dirname(reportFilePath), { recursive: true });
106    await fs.promises.writeFile(reportFilePath, JSON.stringify(reportData, null, 2));
107  } catch (error) {
108    console.error('Error generating report file:', error);
109  }
110}
111
112export function generateReportFileSync(reportName: string, reportData: any, reportPath?: string): void {
113  let reportFilePath = reportName;
114  if (reportPath !== undefined) {
115    reportFilePath = path.join(path.normalize(reportPath), reportName);
116  }
117  try {
118    fs.mkdirSync(path.dirname(reportFilePath), { recursive: true });
119    fs.writeFileSync(reportFilePath, JSON.stringify(reportData, null, 2));
120  } catch (error) {
121    console.error('Error generating report file:', error);
122  }
123}
124
125export function getMapValueSum(map: Map<any, number>): number {
126  let result = 0;
127  for (const value of map.values()) {
128    result += value;
129  }
130  return result;
131}
132
133export async function generateScanProbelemStatisticsReport(
134  statisticsReportInPutInfo: StatisticsReportInPutInfo
135): Promise<void> {
136  const canBeAutoFixedproblemNumbers = getMapValueSum(statisticsReportInPutInfo.ruleToAutoFixedNumbersMap);
137  const problemNumbers: ProblemNumbersInfo = {
138    totalProblemNumbers: statisticsReportInPutInfo.totalProblemNumbers,
139    arkOnePointOneProblemNumbers: statisticsReportInPutInfo.arkOnePointOneProblemNumbers,
140    arkOnePointTWOProblemNumbers:
141      statisticsReportInPutInfo.totalProblemNumbers - statisticsReportInPutInfo.arkOnePointOneProblemNumbers,
142    canBeAutoFixedproblemNumbers: canBeAutoFixedproblemNumbers,
143    needToManualFixproblemNumbers: statisticsReportInPutInfo.totalProblemNumbers - canBeAutoFixedproblemNumbers
144  };
145  const projectFolderList = statisticsReportInPutInfo.cmdOptions.linterOptions.projectFolderList!;
146  const WorkLoadInfo = await getWorkLoadInfo(projectFolderList);
147  const statisticsReportData = getProblemStatisticsInfo(
148    problemNumbers,
149    statisticsReportInPutInfo.ruleToNumbersMap,
150    statisticsReportInPutInfo.ruleToAutoFixedNumbersMap,
151    statisticsReportInPutInfo.timeRecorder,
152    WorkLoadInfo
153  );
154  await generateReportFile(
155    statisticsReportInPutInfo.statisticsReportName,
156    statisticsReportData,
157    statisticsReportInPutInfo.cmdOptions.outputFilePath
158  );
159}
160
161export function generateMigrationStatisicsReport(
162  lintResult: LintRunResult,
163  timeRecorder: TimeRecorder,
164  outputFilePath?: string
165): void {
166  const ruleToNumbersMap: Map<string, number> = new Map();
167  const ruleToAutoFixedNumbersMap: Map<string, number> = new Map();
168  let arkOnePointOneProblemNumbers: number = 0;
169
170  const problemsInfoAfterAutofixed = lintResult.problemsInfos;
171  for (const problems of problemsInfoAfterAutofixed.values()) {
172    accumulateRuleNumbers(problems, ruleToNumbersMap, ruleToAutoFixedNumbersMap);
173    arkOnePointOneProblemNumbers = arkOnePointOneProblemNumbers + getArktsOnePointOneProlemNumbers(problems);
174  }
175
176  let totalProblemNumbers: number = 0;
177  for (const problems of problemsInfoAfterAutofixed.values()) {
178    totalProblemNumbers += problems.length;
179  }
180
181  const canBeAutoFixedproblemNumbers = getMapValueSum(ruleToAutoFixedNumbersMap);
182
183  const problemNumbers: ProblemNumbersInfo = {
184    totalProblemNumbers: totalProblemNumbers,
185    arkOnePointOneProblemNumbers: arkOnePointOneProblemNumbers,
186    arkOnePointTWOProblemNumbers: totalProblemNumbers - arkOnePointOneProblemNumbers,
187    canBeAutoFixedproblemNumbers: canBeAutoFixedproblemNumbers,
188    needToManualFixproblemNumbers: totalProblemNumbers - canBeAutoFixedproblemNumbers
189  };
190
191  const statisticsReportData = getProblemStatisticsInfo(
192    problemNumbers,
193    ruleToNumbersMap,
194    ruleToAutoFixedNumbersMap,
195    timeRecorder
196  );
197  const statisticsReportName: string = 'migration-results-statistics.json';
198  generateReportFileSync(statisticsReportName, statisticsReportData, outputFilePath);
199}
200
201export async function getWorkLoadInfo(projectPathList: string[]): Promise<WorkLoadInfo> {
202  const workloadInfo = new WorkLoadInfo();
203  const projectResults = await Promise.all(
204    projectPathList.map(async(projectPath) => {
205      const normalizedPath = path.normalize(projectPath);
206      const [countFilesResults, countNapiFileResults] = await Promise.all([
207        countFiles(normalizedPath),
208        countNapiFiles(normalizedPath)
209      ]);
210
211      const getLines = (lang: keyof typeof countFilesResults): number => {
212        return countFilesResults[lang]?.lineCount || 0;
213      };
214
215      return {
216        normalizedPath,
217        arkTSCodeLines: getLines('ArkTS') + getLines('ArkTS Test'),
218        cAndCPPCodeLines: getLines('C/C++'),
219        napiCodeLines: countNapiFileResults.napiLines,
220        jsCodeLines: getLines('JavaScript'),
221        tsCodeLines: getLines('TypeScript'),
222        jsonCodeLines: getLines('JSON'),
223        xmlCodeLines: getLines('XML')
224      };
225    })
226  );
227
228  projectResults.forEach((result) => {
229    workloadInfo.addFloderResult(result);
230  });
231  return workloadInfo;
232}
233