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