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 { Dollars, isMemoAnnotation } from '../utils'; 18import { CustomComponentNames } from '../utils'; 19import { DecoratorNames, isDecoratorAnnotation } from '../property-translators/utils'; 20 21export type ScopeInfoCollection = { 22 customComponents: CustomComponentScopeInfo[]; 23}; 24 25export type CustomComponentScopeInfo = { 26 name: string; 27 hasInitializeStruct?: boolean; 28 hasUpdateStruct?: boolean; 29 hasReusableRebind?: boolean; 30}; 31 32/** 33 * Determine whether it is a custom component. 34 * 35 * @param node class declaration node 36 */ 37export function isCustomComponentClass(node: arkts.ClassDeclaration): boolean { 38 if (!node.definition?.ident?.name) { 39 return false; 40 } 41 const name: string = node.definition.ident.name; 42 const structCollection: Set<string> = arkts.GlobalInfo.getInfoInstance().getStructCollection(); 43 return name === CustomComponentNames.COMPONENT_CLASS_NAME || structCollection.has(name); 44} 45 46/** 47 * Determine whether it is method with specified name. 48 * 49 * @param method method definition node 50 * @param name specified method name 51 */ 52export function isKnownMethodDefinition(method: arkts.MethodDefinition, name: string): boolean { 53 if (!method || !arkts.isMethodDefinition(method)) { 54 return false; 55 } 56 57 // For now, we only considered matched method name. 58 const isNameMatched: boolean = method.name?.name === name; 59 return isNameMatched; 60} 61 62/** 63 * Determine whether it is ETSGLOBAL class. 64 * 65 * @param node class declaration node 66 */ 67export function isEtsGlobalClass(node: arkts.ClassDeclaration): boolean { 68 if (node.definition?.ident?.name === 'ETSGLOBAL') { 69 return true; 70 } 71 return false; 72} 73 74/** 75 * Determine whether it is resource node begin with '$r' or '$rawfile'. 76 * 77 * @param node call expression node 78 */ 79export function isReourceNode(node: arkts.CallExpression): boolean { 80 if (node.expression.dumpSrc() === Dollars.DOLLAR_RESOURCE || node.expression.dumpSrc() === Dollars.DOLLAR_RAWFILE) { 81 return true; 82 } 83 return false; 84} 85 86export function isMemoCall(node: arkts.AstNode): node is arkts.CallExpression { 87 if (!arkts.isCallExpression(node)) { 88 return false; 89 } 90 const expr: arkts.AstNode = node.expression; 91 const decl: arkts.AstNode | undefined = arkts.getDecl(expr); 92 93 if (!decl) { 94 return false; 95 } 96 97 if (arkts.isMethodDefinition(decl)) { 98 return decl.scriptFunction.annotations.some( 99 (anno) => isDecoratorAnnotation(anno, DecoratorNames.BUILDER) || isMemoAnnotation(anno, 'memo') 100 ); 101 } 102 return false; 103} 104 105export function findCanAddMemoFromArrowFunction(node: arkts.AstNode): node is arkts.ArrowFunctionExpression { 106 if (!arkts.isArrowFunctionExpression(node)) { 107 return false; 108 } 109 const hasMemo: boolean = node.annotations.some((anno) => isMemoAnnotation(anno, 'memo')); 110 if (!hasMemo && !!node.scriptFunction.body && arkts.isBlockStatement(node.scriptFunction.body)) { 111 return node.scriptFunction.body.statements.some( 112 (st) => arkts.isExpressionStatement(st) && isMemoCall(st.expression) 113 ); 114 } 115 return false; 116} 117