* Copyright (c) 2024 - 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Logger, { LOG_LEVEL, LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { Command, OptionValues } from 'commander';
import { SceneConfig, Sdk } from 'arkanalyzer/lib/Config';
import { AliasType, NullType, NumberType, Scene, Type, UndefinedType } from 'arkanalyzer';
import { PrimitiveType, UnionType } from 'arkanalyzer/lib';
const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'Utils');
export class Utils {
* 解析命令行选项
* @param args 命令行参数数组
* @returns 解析后的选项值
*/
static parseCliOptions(args: string[]): OptionValues {
logger.info('Parse cli options.');
const program = new Command();
return this.getCliOptions(program, args);
}
* 获取命令行选项
* @param program Command 对象
* @param args 命令行参数数组
* @returns 选项值对象
*/
static getCliOptions(program: Command, args: string[]): OptionValues {
program
.option('--configPath <configPath>', 'rule config path')
.option('--projectConfigPath <projectConfigPath>', 'project config path')
.option('--depGraphOutputDir <depGraphOutputDir>', 'output directory of dependency graph')
.parse(args);
return program.opts();
}
* 设置日志路径
* @param logPath 日志路径
*/
static setLogPath(logPath: string): void {
Logger.configure(logPath, LOG_LEVEL.INFO, LOG_LEVEL.INFO);
}
* 设置日志信息,包含路径、arkanalyzer日志级别、homecheck日志级别
*/
static setLogConfig(logPath: string, aaLevel: LOG_LEVEL, hcLevel: LOG_LEVEL): void {
Logger.configure(logPath, aaLevel, hcLevel);
}
* 获取枚举类型的值
* @param value - 枚举值,可以是字符串或数字
* @param enumType - 枚举类型
* @returns 枚举值对应的枚举类型值
*/
static getEnumValues(value: string | number, enumType: any): any {
const key = Object.keys(enumType).find(k => k.toLowerCase() === value || enumType[k as string] === value);
return enumType[key as string];
}
* 按行号和列号对键值对进行排序
* @param keyA 格式为 "行号%列号%规则ID" 的字符串
* @param keyB 格式为 "行号%列号%规则ID" 的字符串
* @returns 排序比较结果
*/
public static sortByLineAndColumn(keyA: string, keyB: string): number {
const [lineA, colA] = keyA.split('%', 2).map(Number);
const [lineB, colB] = keyB.split('%', 2).map(Number);
if (lineA !== lineB) {
return lineA - lineB;
}
return colA - colB;
}
public static generateSceneForEts2SDK(sdks: Sdk[]): Scene {
const sceneConfig: SceneConfig = new SceneConfig();
sceneConfig.buildConfig('ets2SDK', '', sdks);
sceneConfig.getOptions().enableBuiltIn = false;
const scene = new Scene();
scene.buildSceneFromProjectDir(sceneConfig);
return scene;
}
static isUnionTypeContainsType(unionType: UnionType, targetType: Type): boolean {
for (const t of unionType.getTypes()) {
if (t === targetType) {
return true;
}
}
return false;
}
* 检查给出的类型是否是NumberType,或numberType与null、undefined的联合类型
*/
static isNearlyNumberType(checkType: Type): boolean {
if (checkType instanceof AliasType) {
checkType = checkType.getOriginalType();
}
if (checkType instanceof NumberType) {
return true;
}
if (!(checkType instanceof UnionType)) {
return false;
}
const types = checkType.getTypes();
return !types.some(t => {
if (t instanceof NumberType || t instanceof UndefinedType || t instanceof NullType) {
return false;
}
if (t instanceof UnionType) {
return !this.isNearlyNumberType(t);
}
return true;
});
}
* 检查给出的类型是否是内置类型,或内置类型与null、undefined的联合类型
*/
static isNearlyPrimitiveType(checkType: Type): boolean {
if (checkType instanceof PrimitiveType) {
return true;
}
if (checkType instanceof UnionType) {
for (const t of checkType.getTypes()) {
if (t instanceof PrimitiveType || t instanceof UndefinedType || t instanceof NullType) {
continue;
}
if (t instanceof UnionType) {
if (!this.isNearlyPrimitiveType(t)) {
return false;
}
continue;
}
return false;
}
return true;
}
return false;
}
}
export type WarnInfo = {
line: number;
startCol: number;
endLine?: number;
endCol: number;
filePath: string;
};