• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 - 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 { ArkFile } from 'arkanalyzer';
17import { CheckEntry } from './CheckEntry';
18import { ConfigUtils } from './ConfigUtils';
19import { CheckerUtils } from '../checker/CheckerUtils';
20import { file2CheckRuleMap, project2CheckRuleMap } from './CheckerIndex';
21import { Rule } from '../../model/Rule';
22import { RuleConfig } from '../../model/RuleConfig';
23import { fileCheckBuilder, projectCheckBuilder } from './CheckBuilder';
24import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
25import { FileUtils } from './FileUtils';
26
27const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'fileRuleMapping');
28
29export async function fileRuleMapping(checkFileList: string[], checkEntry: CheckEntry): Promise<boolean> {
30    // 获取规则配置文件的规则,除了override
31    const allRulesMap = ConfigUtils.getRuleMap(checkEntry.ruleConfig, checkEntry.projectConfig, checkEntry.message);
32    if (allRulesMap.size === 0) {
33        checkEntry.message?.progressNotify(1, 'No rule to check');
34        return false;
35    }
36
37    let arkFiles: ArkFile[] = [];
38    const fiRulesMap: Map<string, Rule> = new Map();
39    const fileRulesMap = await createFileRulesMap(checkFileList, allRulesMap, checkEntry, file2CheckRuleMap, fiRulesMap);
40    for (const filePath of checkFileList) {
41        try {
42            const arkFile = CheckerUtils.getArkFileByFilePath(checkEntry.scene, filePath);
43            if (!arkFile) {
44                continue;
45            }
46
47            arkFiles.push(arkFile);
48            const enabledRules = fileRulesMap.get(filePath);
49            if (enabledRules) {
50                checkEntry.addFileCheck(fileCheckBuilder(arkFile, enabledRules));
51            }
52        } catch (error) {
53            logger.error(`Error processing file ${filePath}: ${(error as Error).message}`);
54        }
55    }
56
57    const proRulesMap: Map<string, Rule> = new Map();
58    const projectRulesMap = await createFileRulesMap(checkFileList, allRulesMap, checkEntry, project2CheckRuleMap, proRulesMap);
59    const projectRules = Array.from(proRulesMap.values());
60    try {
61        checkEntry.addProjectCheck(projectCheckBuilder(arkFiles, projectRules));
62        checkEntry.projectCheck.ruleMap = projectRulesMap;
63    } catch (error) {
64        logger.error(`Error adding project check: ${(error as Error).message}`);
65    }
66    return true;
67}
68
69function filterRule(allRulesMap: Map<string, Rule>, filterMap?: Map<string, Rule[]>): Rule[] {
70    const rules: Rule[] = [];
71    for (const [key, value] of allRulesMap) {
72        if (filterMap && !filterMap.has(key)) {
73            continue;
74        }
75        rules.push(value);
76    }
77    return rules;
78}
79
80async function createFileRulesMap(allFiles: string[], allRulesMap: Map<string, Rule>, checkEntry: CheckEntry,
81    checksRuleMap: Map<string, any>, proRulesMap: Map<string, Rule>): Promise<Map<string, Rule[]>> {
82    // 获取配置的规则列表
83    let fileRulesMap: Map<string, Rule[]> = new Map();
84    const ruleMap = filterRule(allRulesMap, checksRuleMap);
85
86    const defaultRules = Array.from(ruleMap.values());
87    allFiles.forEach(filePath => fileRulesMap.set(filePath, defaultRules));
88    ruleMap.forEach(rule => {
89        proRulesMap.set(rule.ruleId, rule);
90    });
91    // 检查额外规则覆盖
92    for (const override of checkEntry.ruleConfig.overrides ?? []) {
93        try {
94            const overrideFileRulesMap = await createFileRulesMapWithOverride(checkEntry, override, checksRuleMap, proRulesMap);
95            fileRulesMap = mergeFileRulesMap(fileRulesMap, overrideFileRulesMap);
96        } catch (error) {
97            logger.error(`Error check extra rule overrides: ${(error as Error).message}`);
98        }
99    }
100    return fileRulesMap;
101}
102
103async function createFileRulesMapWithOverride(checkEntry: CheckEntry, override: RuleConfig,
104    checksRuleMap: Map<string, any>, proRulesMap: Map<string, Rule>): Promise<Map<string, Rule[]>> {
105    let checkFileList = checkEntry.selectFileList.map(file => file.filePath);
106    if (checkFileList.length === 0) {
107        checkFileList = FileUtils.getAllFiles(checkEntry.projectConfig.projectPath, ['.ts', '.ets', '.json5']);
108    }
109    checkFileList = await FileUtils.getFiltedFiles(checkFileList, override);
110    const allRuleMap = ConfigUtils.getRuleMap(override, checkEntry.projectConfig, checkEntry.message);
111    const ruleMap = filterRule(allRuleMap, checksRuleMap);
112    ruleMap.forEach(rule => {
113        if (!proRulesMap.has(rule.ruleId)) {
114            proRulesMap.set(rule.ruleId, rule);
115        }
116    });
117    const fileRulesMap: Map<string, Rule[]> = new Map();
118    const defaultRules = Array.from(ruleMap.values());
119    checkFileList.forEach(filePath => fileRulesMap.set(filePath, defaultRules));
120    return fileRulesMap;
121}
122
123function mergeFileRulesMap(fileRulesMap: Map<string, Rule[]>,
124    overrideFileRulesMap: Map<string, Rule[]>): Map<string, Rule[]> {
125    // 取fileRule和overrideRule交集
126    for (const [key, vals] of overrideFileRulesMap) {
127        if (!fileRulesMap.has(key) || vals.length === 0) {
128            continue;
129        }
130        let fileRules = fileRulesMap.get(key);
131        if (!fileRules || fileRules.length === 0) {
132            fileRulesMap.set(key, vals);
133            continue;
134        }
135        let newRules = [...fileRules];
136        vals.forEach(val => {
137            let existIndex = fileRules?.findIndex(fileRule => fileRule.ruleId === val.ruleId);
138            if (existIndex === undefined || existIndex === -1) {
139                newRules.push(val);
140            } else {
141                newRules[existIndex] = val;
142            }
143        });
144        fileRulesMap.set(key, newRules);
145    }
146    // 筛除关闭的rule
147    const filteredRulesMap = new Map<string, Rule[]>();
148    for (const [key, rules] of fileRulesMap) {
149        const filteredRules = rules.filter(rule => rule.alert !== 0);
150        filteredRulesMap.set(key, filteredRules);
151    }
152    return filteredRulesMap;
153}