1/* 2 * Copyright (c) 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 * as arkts from '@koalaui/libarkts'; 17import * as fs from 'fs'; 18import * as path from 'path'; 19 20export const PresetDecorators = { 21 BUILDER_PARAM: 'BuilderParam', 22 COMPONENT_V1: 'Component', 23 COMPONENT_V2: 'ComponentV2', 24 COMPUTED: 'Computed', 25 CONSUME: 'Consume', 26 CONSUMER: 'Consumer', 27 CUSTOM_DIALOG: 'CustomDialog', 28 ENTRY: 'Entry', 29 EVENT: 'Event', 30 PREVIEW: 'Preview', 31 STATE: 'State', 32 PARAM: 'Param', 33 PROP: 'Prop', 34 PROVIDE: 'Provide', 35 PROVIDER: 'Provider', 36 LINK: 'Link', 37 LOCAL: 'Local', 38 OBJECT_LINK: 'ObjectLink', 39 STORAGE_PROP: 'StorageProp', 40 STORAGE_LINK: 'StorageLink', 41 LOCAL_STORAGE_PROP: 'LocalStorageProp', 42 LOCAL_STORAGE_LINK: 'LocalStorageLink', 43 REQUIRE: 'Require', 44 REUSABLE_V1: 'Reusable', 45 REUSABLE_V2: 'ReusableV2', 46 OBSERVED_V1: 'Observed', 47 OBSERVED_V2: 'ObservedV2', 48 TYPE: 'Type', 49 WATCH: 'Watch', 50 BUILDER: 'Builder', 51 TRACK: 'Track', 52 TRACE: 'Trace', 53 ONCE: 'Once', 54 MONITOR: 'Monitor', 55 LOCAL_BUILDER: 'LocalBuilder', 56}; 57 58const PUBLIC_PROPERTY_MODIFIERS: Number = 4; 59const PROTECTED_PROPERTY_MODIFIERS: Number = 8; 60const PRIVATE_PROPERTY_MODIFIERS: Number = 16; 61export function getIdentifierName(node: arkts.AstNode): string { 62 if (!arkts.isIdentifier(node)) { 63 throw new Error(`Except a Identifier type!`); 64 } 65 return node.name; 66} 67 68export function getAnnotationName(annotation: arkts.AnnotationUsage): string { 69 if (!annotation.expr) { 70 throw new Error(`The expr property does not exist!`); 71 } 72 return getIdentifierName(annotation.expr); 73} 74 75export function getAnnotationUsage( 76 declaration: arkts.StructDeclaration, 77 annotationName: string, 78): arkts.AnnotationUsage | undefined { 79 return declaration.definition.annotations.find( 80 (annotation) => 81 annotation.expr && 82 arkts.isIdentifier(annotation.expr) && 83 annotation.expr.name === annotationName, 84 ); 85} 86 87export function getClassAnnotationUsage( 88 declaration: arkts.ClassDeclaration, 89 annotationName: string, 90): arkts.AnnotationUsage | undefined { 91 if (!declaration.definition || !declaration.definition.annotations) { 92 return undefined; 93 } 94 return declaration.definition.annotations.find( 95 (annotation) => 96 annotation.expr && 97 ((arkts.isIdentifier(annotation.expr) && annotation.expr.name === annotationName) || 98 (arkts.isCallExpression(annotation.expr) && 99 arkts.isIdentifier(annotation.expr) && 100 annotation.expr.name === annotationName)) 101 ); 102} 103 104 105 106export function getClassPropertyName(property: arkts.ClassProperty): string { 107 return getIdentifierName(property.key); 108} 109 110export function getClassPropertyType(property: arkts.ClassProperty): string { 111 return property.typeAnnotation.dumpSrc(); 112} 113 114export function getClassPropertyAnnotationNames( 115 property: arkts.ClassProperty, 116): string[] { 117 return property.annotations.map((annotation) => 118 getAnnotationName(annotation), 119 ); 120} 121 122export function isPublicClassProperty(property: arkts.ClassProperty): boolean { 123 // todo 使用接口实现 124 return property.modifiers === PUBLIC_PROPERTY_MODIFIERS; 125} 126 127export function isPrivateClassProperty(property: arkts.ClassProperty): boolean { 128 // todo 使用接口实现 129 return property.modifiers === PRIVATE_PROPERTY_MODIFIERS; 130} 131 132export function isProtectedlassProperty(property: arkts.ClassProperty): boolean { 133 // todo 使用接口实现 134 return property.modifiers === PROTECTED_PROPERTY_MODIFIERS; 135} 136 137export class MultiMap<K, V> { 138 private readonly map: Map<K, V[]>; 139 constructor() { 140 this.map = new Map(); 141 } 142 /** 143 * Add key-value pairs to MultiMap 144 * @param key key 145 * @param value value 146 */ 147 add(key: K, value: V): void { 148 if (!this.map.has(key)) { 149 this.map.set(key, []); 150 } 151 this.map.get(key)!.push(value); 152 } 153 154 /** 155 * Gets all the values of the specified key 156 * @param key key 157 * @returns An array of values, which returns an empty array if the key does not exist 158 */ 159 get(key: K): V[] { 160 return this.map.get(key) || []; 161 } 162 163 /** 164 * Check if the specified key exists in the MultiMap 165 * @param key key 166 * @returns Whether it exists 167 */ 168 has(key: K): boolean { 169 return this.map.has(key); 170 } 171} 172 173interface ComponentJson { 174 name: string; 175 atomic?: boolean; 176 attrs: string[]; 177} 178 179export function getContainerComponents(dirPath: string): Set<string> { 180 const resultSet = new Set<string>(); 181 const absolutePath = path.resolve(__dirname, dirPath); 182 183 if (!fs.existsSync(absolutePath)) { 184 throw new Error(`Directory does not exist: ${absolutePath}`); 185 } 186 // Read all files in the directory 187 const files = fs.readdirSync(absolutePath); 188 189 files.forEach(file => { 190 if (path.extname(file) === '.json') { 191 const filePath = path.join(absolutePath, file); 192 const fileContent = fs.readFileSync(filePath, 'utf-8'); 193 const componentJson: ComponentJson = JSON.parse(fileContent); 194 if ((!componentJson.atomic || componentJson.atomic !== true) && (componentJson.name)) { 195 resultSet.add(componentJson.name); 196 } 197 } 198 }); 199 return resultSet; 200}