• 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 { ArkField, ArkFile, ArkMethod, ArkNamespace, Scene } from 'arkanalyzer';
17import { ArkClass, ClassCategory } from 'arkanalyzer/lib/core/model/ArkClass';
18
19export enum MethodCategory {
20    Accessor = 0,
21    ArrowFunction = 1,
22    FunctionExpression = 2,
23    Constructor = 3
24}
25
26export enum MatcherTypes {
27    FILE = 0,
28    NAMESPACE = 1,
29    CLASS = 2,
30    METHOD = 3,
31    FIELD = 4,
32    EXPR = 5
33}
34
35export interface BaseMatcher {
36    [matchFieldName: string]: any;
37}
38
39//TODO: move to FileMatcher.ts
40export interface FileMatcher extends BaseMatcher {
41    readonly matcherType: MatcherTypes.FILE;
42    name?: string;
43}
44
45export interface NamespaceMatcher extends BaseMatcher {
46    readonly matcherType: MatcherTypes.NAMESPACE;
47    name?: string[];
48    file?: (FileMatcher | ArkFile)[];
49    namespace?: (NamespaceMatcher | ArkNamespace)[];
50    isExport?: boolean;
51}
52
53export interface ClassMatcher extends BaseMatcher {
54    readonly matcherType: MatcherTypes.CLASS;
55    name?: string[];
56    file?: (FileMatcher | ArkFile)[];
57    namespace?: (NamespaceMatcher | ArkNamespace)[];
58    category?: ClassCategory[];
59    isAbstract?: boolean;
60    isExport?: boolean;
61    extends?: (ClassMatcher | ArkClass)[];
62    implements?: (ClassMatcher | ArkClass)[];
63    hasViewTree?: boolean;
64}
65
66export interface MethodMatcher extends BaseMatcher {
67    readonly matcherType: MatcherTypes.METHOD;
68    name?: string[];
69    file?: (FileMatcher | ArkFile)[];
70    namespace?: (NamespaceMatcher | ArkNamespace)[];
71    class?: (ClassMatcher | ArkClass)[];
72    category?: MethodCategory[];
73    decorators?: string[];
74    isStatic?: boolean;
75    isExport?: boolean;
76    isPublic?: boolean;
77    isPrivate?: boolean;
78    isProtected?: boolean;
79    isAbstract?: boolean;
80    hasViewTree?: boolean;
81    isAnonymous?: boolean;
82}
83
84export interface FieldMatcher extends BaseMatcher {
85    readonly matcherType: MatcherTypes.FIELD;
86    name?: string[];
87    file?: (FileMatcher | ArkFile)[];
88    namespace?: (NamespaceMatcher | ArkNamespace)[];
89    class?: (ClassMatcher | ArkClass)[];
90    decorators?: string[];
91    isStatic?: boolean;
92    isPublic?: boolean;
93    isPrivate?: boolean;
94    isProtected?: boolean;
95    isReadonly?: boolean;
96}
97
98export interface MatcherCallback {
99    matcher: BaseMatcher | undefined,
100    callback: Function
101}
102
103export function isMatchedFile(arkFile: ArkFile, matchers: (FileMatcher | ArkFile)[]): boolean {
104    for (const fileMatcher of matchers) {
105        if (fileMatcher instanceof ArkFile) {
106            if (arkFile === fileMatcher) {
107                return true;
108            }
109        } else {
110            if (fileMatcher.name && arkFile.getName() !== fileMatcher.name) {
111                continue;
112            }
113            return true;
114        }
115    }
116    return false;
117}
118
119export function isMatchedNamespace(arkNs: ArkNamespace | null | undefined, matchers: (NamespaceMatcher | ArkNamespace)[]): boolean {
120    if (!arkNs) {
121        return false;
122    }
123
124    for (const nsMatcher of matchers) {
125        if (nsMatcher instanceof ArkNamespace) {
126            if (arkNs === nsMatcher) {
127                return true;
128            }
129        } else {
130            if (nsMatcher.file && !isMatchedFile(arkNs.getDeclaringArkFile(), nsMatcher.file) ||
131                nsMatcher.namespace && !isMatchedNamespace(arkNs.getDeclaringArkNamespace(), nsMatcher.namespace) ||
132                nsMatcher.name && !nsMatcher.name.includes(arkNs.getName()) ||
133                nsMatcher.isExported !== undefined && nsMatcher.isExported !== arkNs.isExport()) {
134                continue;
135            }
136            // todo: 未考虑嵌套ns场景
137            return true;
138        }
139    }
140    return false;
141}
142
143export function isMatchedClass(arkClass: ArkClass | null | undefined, matchers: (ClassMatcher | ArkClass)[]): boolean {
144    if (!arkClass) {
145        return false;
146    }
147    for (const classMatcher of matchers) {
148        if (classMatcher instanceof ArkClass) {
149            if (arkClass === classMatcher) {
150                return true;
151            }
152        } else {
153            if (classMatcher.file && !isMatchedFile(arkClass.getDeclaringArkFile(), classMatcher.file) ||
154                classMatcher.namespace && !isMatchedNamespace(arkClass.getDeclaringArkNamespace(), classMatcher.namespace) ||
155                classMatcher.name && !classMatcher.name.includes(arkClass.getName()) ||
156                classMatcher.category && !classMatcher.category.includes(arkClass.getCategory()) ||
157                classMatcher.isAbstract !== undefined && classMatcher.isAbstract !== arkClass.isAbstract() ||
158                classMatcher.isExport !== undefined && classMatcher.isExport !== arkClass.isExport() ||
159                classMatcher.hasViewTree !== undefined && classMatcher.hasViewTree !== arkClass.hasViewTree() ||
160                // classMatcher.implements && !isMatchedClass(arkClass.getImplementedInterfaces(), classMatcher.implements) ||
161                classMatcher.extends && !isMatchedClass(arkClass.getSuperClass(), classMatcher.extends)) {
162                continue;
163            }
164            return true;
165        }
166    }
167    return false;
168}
169
170export function isMatchedMethod(arkMethod: ArkMethod | null | undefined, matchers: (MethodMatcher | ArkMethod)[]): boolean {
171    if (!arkMethod) {
172        return false;
173    }
174    for (const mtdMatcher of matchers) {
175        if (mtdMatcher instanceof ArkMethod) {
176            if (mtdMatcher === arkMethod) {
177                return true;
178            }
179        } else {
180            if (mtdMatcher.file && !isMatchedFile(arkMethod.getDeclaringArkFile(), mtdMatcher.file) ||
181                mtdMatcher.namespace && !isMatchedNamespace(arkMethod.getDeclaringArkClass().getDeclaringArkNamespace(), mtdMatcher.namespace) ||
182                mtdMatcher.class && !isMatchedClass(arkMethod.getDeclaringArkClass(), mtdMatcher.class) ||
183                // mtdMatcher.category && !mtdMatcher.category.includes(arkMethod.getCategory()) ||
184                mtdMatcher.isAnonymous && !arkMethod.isAnonymousMethod() ||
185                mtdMatcher.name && !mtdMatcher.name.includes(arkMethod.getName()) ||
186                mtdMatcher.decorators && !arkMethod.getDecorators().some(d => mtdMatcher.decorators!.includes(d.getKind())) ||
187                mtdMatcher.isStatic !== undefined && mtdMatcher.isStatic !== arkMethod.isStatic() ||
188                mtdMatcher.isExport !== undefined && mtdMatcher.isExport !== arkMethod.isExport() ||
189                mtdMatcher.isPublic !== undefined && mtdMatcher.isPublic !== arkMethod.isPublic() ||
190                mtdMatcher.isPrivate !== undefined && mtdMatcher.isPrivate !== arkMethod.isPrivate() ||
191                mtdMatcher.isProtected !== undefined && mtdMatcher.isProtected !== arkMethod.isProtected() ||
192                mtdMatcher.hasViewTree !== undefined && mtdMatcher.hasViewTree !== arkMethod.hasViewTree() ||
193                mtdMatcher.isAbstract !== undefined && mtdMatcher.isAbstract !== arkMethod.isAbstract()) {
194                continue;
195            }
196            return true;
197        }
198    }
199    return false;
200}
201
202export function isMatchedField(arkField: ArkField | null | undefined, matchers: (FieldMatcher | ArkField)[]): boolean {
203    if (!arkField) {
204        return false;
205    }
206    for (const fieldMatcher of matchers) {
207        if (fieldMatcher instanceof ArkField) {
208            if (fieldMatcher === arkField) {
209                return true;
210            }
211        } else {
212            if (fieldMatcher.file && !isMatchedFile(arkField.getDeclaringArkClass().getDeclaringArkFile(), fieldMatcher.file) ||
213                fieldMatcher.namespace && !isMatchedNamespace(arkField.getDeclaringArkClass().getDeclaringArkNamespace(), fieldMatcher.namespace) ||
214                fieldMatcher.class && !isMatchedClass(arkField.getDeclaringArkClass(), fieldMatcher.class) ||
215                fieldMatcher.name && !fieldMatcher.name.includes(arkField.getName()) ||
216                fieldMatcher.decorators && !arkField.getDecorators().some(d => fieldMatcher.decorators!.includes(d.getKind())) ||
217                fieldMatcher.isStatic !== undefined && fieldMatcher.isStatic !== arkField.isStatic() ||
218                fieldMatcher.isPublic !== undefined && fieldMatcher.isPublic !== arkField.isPublic() ||
219                fieldMatcher.isPrivate !== undefined && fieldMatcher.isPrivate !== arkField.isPrivate() ||
220                fieldMatcher.isProtected !== undefined && fieldMatcher.isProtected !== arkField.isProtected()) {
221                continue;
222            }
223            return true;
224        }
225    }
226    return false;
227}