• 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 ts from 'ohos-typescript';
17import { Decorator } from '../base/Decorator';
18import { COMPONENT_DECORATOR, ENTRY_DECORATOR, BUILDER_PARAM_DECORATOR, BUILDER_DECORATOR } from '../common/EtsConst';
19import { ArkError, ArkErrorCode } from '../common/ArkError';
20import Logger, { LOG_MODULE_TYPE } from '../../utils/logger';
21import { ArkMetadata, ArkMetadataKind, ArkMetadataType } from './ArkMetadata';
22const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'ArkBaseModel');
23
24const COMPONENT_MEMBER_DECORATORS: Set<string> = new Set([
25    'State',
26    'Prop',
27    'Link',
28    'StorageProp',
29    'StorageLink',
30    'Provide',
31    'Consume',
32    'ObjectLink',
33    'LocalStorageLink',
34    'LocalStorageProp',
35    'Local',
36    'Param',
37    'Event',
38    'Provider',
39    'Consumer',
40]);
41
42export enum ModifierType {
43    PRIVATE = 1,
44    PROTECTED = 1 << 1,
45    PUBLIC = 1 << 2,
46    EXPORT = 1 << 3,
47    STATIC = 1 << 4,
48    ABSTRACT = 1 << 5,
49    ASYNC = 1 << 6,
50    CONST = 1 << 7,
51    ACCESSOR = 1 << 8,
52    DEFAULT = 1 << 9,
53    IN = 1 << 10,
54    READONLY = 1 << 11,
55    OUT = 1 << 12,
56    OVERRIDE = 1 << 13,
57    DECLARE = 1 << 14,
58}
59
60export const MODIFIER_TYPE_MASK = 0xffff;
61
62const MODIFIER_TYPE_STRINGS = [
63    'private',
64    'protected',
65    'public',
66    'export',
67    'static',
68    'abstract',
69    'async',
70    'const',
71    'accessor',
72    'default',
73    'in',
74    'readonly',
75    'out',
76    'override',
77    'declare',
78];
79
80const MODIFIER_KIND_2_ENUM = new Map<ts.SyntaxKind, ModifierType>([
81    [ts.SyntaxKind.AbstractKeyword, ModifierType.ABSTRACT],
82    [ts.SyntaxKind.AccessorKeyword, ModifierType.ACCESSOR],
83    [ts.SyntaxKind.AsyncKeyword, ModifierType.ASYNC],
84    [ts.SyntaxKind.ConstKeyword, ModifierType.CONST],
85    [ts.SyntaxKind.DeclareKeyword, ModifierType.DECLARE],
86    [ts.SyntaxKind.DefaultKeyword, ModifierType.DEFAULT],
87    [ts.SyntaxKind.ExportKeyword, ModifierType.EXPORT],
88    [ts.SyntaxKind.InKeyword, ModifierType.IN],
89    [ts.SyntaxKind.PrivateKeyword, ModifierType.PRIVATE],
90    [ts.SyntaxKind.ProtectedKeyword, ModifierType.PROTECTED],
91    [ts.SyntaxKind.PublicKeyword, ModifierType.PUBLIC],
92    [ts.SyntaxKind.ReadonlyKeyword, ModifierType.READONLY],
93    [ts.SyntaxKind.OutKeyword, ModifierType.OUT],
94    [ts.SyntaxKind.OverrideKeyword, ModifierType.OVERRIDE],
95    [ts.SyntaxKind.StaticKeyword, ModifierType.STATIC],
96]);
97
98export function modifierKind2Enum(kind: ts.SyntaxKind): ModifierType {
99    return MODIFIER_KIND_2_ENUM.get(kind)!;
100}
101
102export function modifiers2stringArray(modifiers: number): string[] {
103    let strs: string[] = [];
104    for (let idx = 0; idx < MODIFIER_TYPE_STRINGS.length; idx++) {
105        if (modifiers & 0x01) {
106            strs.push(MODIFIER_TYPE_STRINGS[idx]);
107        }
108        modifiers = modifiers >>> 1;
109    }
110    return strs;
111}
112
113export abstract class ArkBaseModel {
114    protected modifiers?: number;
115    protected decorators?: Set<Decorator>;
116    protected metadata?: ArkMetadata;
117
118    public getMetadata(kind: ArkMetadataKind): ArkMetadataType | undefined {
119        return this.metadata?.getMetadata(kind);
120    }
121
122    public setMetadata(kind: ArkMetadataKind, value: ArkMetadataType): void {
123        if (!this.metadata) {
124            this.metadata = new ArkMetadata();
125        }
126        return this.metadata?.setMetadata(kind, value);
127    }
128
129    public getModifiers(): number {
130        if (!this.modifiers) {
131            return 0;
132        }
133        return this.modifiers;
134    }
135
136    public setModifiers(modifiers: number): void {
137        if (modifiers !== 0) {
138            this.modifiers = modifiers;
139        }
140    }
141
142    public addModifier(modifier: ModifierType | number): void {
143        this.modifiers = this.getModifiers() | modifier;
144    }
145
146    public removeModifier(modifier: ModifierType): void {
147        if (!this.modifiers) {
148            return;
149        }
150        this.modifiers &= MODIFIER_TYPE_MASK ^ modifier;
151    }
152
153    public isStatic(): boolean {
154        return this.containsModifier(ModifierType.STATIC);
155    }
156
157    public isProtected(): boolean {
158        return this.containsModifier(ModifierType.PROTECTED);
159    }
160
161    public isPrivate(): boolean {
162        return this.containsModifier(ModifierType.PRIVATE);
163    }
164
165    public isPublic(): boolean {
166        return this.containsModifier(ModifierType.PUBLIC);
167    }
168
169    public isReadonly(): boolean {
170        return this.containsModifier(ModifierType.READONLY);
171    }
172
173    public isAbstract(): boolean {
174        return this.containsModifier(ModifierType.ABSTRACT);
175    }
176
177    public isExport(): boolean {
178        return this.containsModifier(ModifierType.EXPORT);
179    }
180
181    public isDefault(): boolean {
182        return this.containsModifier(ModifierType.DEFAULT);
183    }
184
185    /** @deprecated Use {@link isExport} instead. */
186    public isExported(): boolean {
187        return this.isExport();
188    }
189
190    public isDeclare(): boolean {
191        return this.containsModifier(ModifierType.DECLARE);
192    }
193
194    public containsModifier(modifierType: ModifierType): boolean {
195        if (!this.modifiers) {
196            return false;
197        }
198
199        return (this.modifiers & modifierType) === modifierType;
200    }
201
202    public getDecorators(): Decorator[] {
203        if (this.decorators) {
204            return Array.from(this.decorators);
205        }
206        return [];
207    }
208
209    public setDecorators(decorators: Set<Decorator>): void {
210        if (decorators.size > 0) {
211            this.decorators = decorators;
212        }
213    }
214
215    public addDecorator(decorator: Decorator): void {
216        if (!this.decorators) {
217            this.decorators = new Set();
218        }
219        this.decorators.add(decorator);
220    }
221
222    public removeDecorator(kind: string): void {
223        this.decorators?.forEach(value => {
224            if (value.getKind() === kind) {
225                this.decorators?.delete(value);
226            }
227        });
228    }
229
230    public hasBuilderDecorator(): boolean {
231        return this.hasDecorator(BUILDER_DECORATOR);
232    }
233
234    public getStateDecorators(): Decorator[] {
235        if (!this.decorators) {
236            return [];
237        }
238        return Array.from(this.decorators).filter(item => {
239            return COMPONENT_MEMBER_DECORATORS.has(item.getKind());
240        }) as Decorator[];
241    }
242
243    public hasBuilderParamDecorator(): boolean {
244        return this.hasDecorator(BUILDER_PARAM_DECORATOR);
245    }
246
247    public hasEntryDecorator(): boolean {
248        return this.hasDecorator(ENTRY_DECORATOR);
249    }
250
251    public hasComponentDecorator(): boolean {
252        return this.hasDecorator(COMPONENT_DECORATOR);
253    }
254
255    public hasDecorator(kind: string | Set<string>): boolean {
256        let decorators = this.getDecorators();
257        return (
258            decorators.filter(value => {
259                if (kind instanceof Set) {
260                    return kind.has(value.getKind());
261                }
262                return value.getKind() === kind;
263            }).length !== 0
264        );
265    }
266
267    protected validateFields(fields: string[]): ArkError {
268        let errs: string[] = [];
269        for (const field of fields) {
270            let value = Reflect.get(this, field);
271            if (!value) {
272                errs.push(field);
273            }
274        }
275        if (errs.length === 0) {
276            return { errCode: ArkErrorCode.OK };
277        }
278        logger.error(`class fields: ${errs.join(',')} is undefined.`);
279        return {
280            errCode: ArkErrorCode.CLASS_INSTANCE_FIELD_UNDEFINDED,
281            errMsg: `${errs.join(',')} is undefined.`,
282        };
283    }
284
285    public abstract validate(): ArkError;
286}
287