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 { BuilderLambdaNames, CustomComponentNames, hasPropertyInAnnotation, hasNullOrUndefinedType } from './utils'; 18import { annotation } from '../common/arkts-utils'; 19import { DecoratorNames, needDefiniteOrOptionalModifier } from './property-translators/utils'; 20 21export class factory { 22 /** 23 * create `instance: <typeName>` as identifier 24 */ 25 static createInstanceIdentifier(typeName: string): arkts.Identifier { 26 return arkts.factory.createIdentifier( 27 BuilderLambdaNames.STYLE_ARROW_PARAM_NAME, 28 factory.createTypeReferenceFromString(typeName) 29 ); 30 } 31 32 /** 33 * create `instance: <typeName>` as parameter 34 */ 35 static createInstanceParameter(typeName: string): arkts.ETSParameterExpression { 36 return arkts.factory.createParameterDeclaration(factory.createInstanceIdentifier(typeName), undefined); 37 } 38 39 /** 40 * create `(instance: <typeName>) => void` 41 */ 42 static createStyleLambdaFunctionType(typeName: string): arkts.ETSFunctionType { 43 return arkts.factory.createFunctionType( 44 arkts.FunctionSignature.createFunctionSignature( 45 undefined, 46 [factory.createInstanceParameter(typeName)], 47 factory.createTypeReferenceFromString(typeName), 48 false 49 ), 50 arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW 51 ); 52 } 53 54 /** 55 * create `style: ((instance: <typeName>) => void) | undefined` as identifier 56 */ 57 static createStyleIdentifier(typeName: string): arkts.Identifier { 58 return arkts.factory.createIdentifier( 59 BuilderLambdaNames.STYLE_PARAM_NAME, 60 arkts.factory.createUnionType([ 61 factory.createStyleLambdaFunctionType(typeName), 62 arkts.factory.createETSUndefinedType(), 63 ]) 64 ); 65 } 66 67 /** 68 * create `@memo() style: ((instance: <typeName>) => void) | undefined` as parameter 69 */ 70 static createStyleParameter(typeName: string): arkts.ETSParameterExpression { 71 const styleParam: arkts.Identifier = factory.createStyleIdentifier(typeName); 72 const param = arkts.factory.createParameterDeclaration(styleParam, undefined); 73 param.annotations = [annotation('memo')]; 74 return param; 75 } 76 77 /** 78 * create `initializers: <optionsName> | undefined` as identifier 79 */ 80 static createInitializerOptionsIdentifier(optionsName: string): arkts.Identifier { 81 return arkts.factory.createIdentifier( 82 CustomComponentNames.COMPONENT_INITIALIZERS_NAME, 83 arkts.factory.createUnionType([ 84 factory.createTypeReferenceFromString(optionsName), 85 arkts.factory.createETSUndefinedType(), 86 ]) 87 ); 88 } 89 90 /** 91 * create `initializers: <optionsName> | undefined` as parameter 92 */ 93 static createInitializersOptionsParameter(optionsName: string): arkts.ETSParameterExpression { 94 return arkts.factory.createParameterDeclaration( 95 factory.createInitializerOptionsIdentifier(optionsName), 96 undefined 97 ); 98 } 99 100 /** 101 * create `content: (() => void) | undefined` as identifier 102 */ 103 static createContentIdentifier(): arkts.Identifier { 104 return arkts.factory.createIdentifier( 105 BuilderLambdaNames.CONTENT_PARAM_NAME, 106 arkts.factory.createUnionType([factory.createLambdaFunctionType(), arkts.factory.createETSUndefinedType()]) 107 ); 108 } 109 110 /** 111 * create `@memo() content: (() => void) | undefined` as parameter 112 */ 113 static createContentParameter(): arkts.ETSParameterExpression { 114 const contentParam: arkts.Identifier = factory.createContentIdentifier(); 115 const param = arkts.factory.createParameterDeclaration(contentParam, undefined); 116 param.annotations = [annotation('memo')]; 117 return param; 118 } 119 120 /** 121 * create type from string 122 */ 123 static createTypeReferenceFromString(name: string): arkts.TypeNode { 124 return arkts.factory.createTypeReference( 125 arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(name)) 126 ); 127 } 128 129 /** 130 * create `(<params>) => <returnType>`. If returnType is not given, then using `void`. 131 */ 132 static createLambdaFunctionType( 133 params?: arkts.Expression[], 134 returnType?: arkts.TypeNode | undefined 135 ): arkts.ETSFunctionType { 136 return arkts.factory.createFunctionType( 137 arkts.FunctionSignature.createFunctionSignature( 138 undefined, 139 params ?? [], 140 returnType ?? arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), 141 false 142 ), 143 arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW 144 ); 145 } 146 147 /** 148 * create and insert `import { <imported> as <local> } from <source>` to the top of script's statements. 149 */ 150 static createAndInsertImportDeclaration( 151 source: arkts.StringLiteral, 152 imported: arkts.Identifier, 153 local: arkts.Identifier, 154 importKind: arkts.Es2pandaImportKinds, 155 program: arkts.Program 156 ): void { 157 const importDecl: arkts.ETSImportDeclaration = arkts.factory.createImportDeclaration( 158 source, 159 [arkts.factory.createImportSpecifier(imported, local)], 160 importKind, 161 program, 162 arkts.Es2pandaImportFlags.IMPORT_FLAGS_NONE 163 ); 164 arkts.importDeclarationInsert(importDecl, program); 165 return; 166 } 167 168 /* 169 * create `import { <imported> as <local> } ...`. 170 */ 171 static createAdditionalImportSpecifier(imported: string, local: string): arkts.ImportSpecifier { 172 return arkts.factory.createImportSpecifier( 173 arkts.factory.createIdentifier(imported), 174 arkts.factory.createIdentifier(local) 175 ); 176 } 177 178 /* 179 * create `constructor() {}`. 180 */ 181 static createConstructorMethod(member: arkts.MethodDefinition): arkts.MethodDefinition { 182 return arkts.factory.createMethodDefinition( 183 arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, 184 member.name, 185 member.scriptFunction, 186 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, 187 false 188 ); 189 } 190 191 /* 192 * create `@memo() _build(<>)`. 193 */ 194 static transformBuildMethodWithOriginBuild( 195 method: arkts.MethodDefinition, 196 typeName: string, 197 optionsName: string, 198 isDecl?: boolean 199 ): arkts.MethodDefinition { 200 const updateKey: arkts.Identifier = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_BUILD); 201 202 const scriptFunction: arkts.ScriptFunction = method.scriptFunction; 203 const updateScriptFunction = arkts.factory 204 .createScriptFunction( 205 scriptFunction.body, 206 arkts.FunctionSignature.createFunctionSignature( 207 scriptFunction.typeParams, 208 [ 209 factory.createStyleParameter(typeName), 210 factory.createContentParameter(), 211 factory.createInitializersOptionsParameter(optionsName), 212 ], 213 arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), 214 false 215 ), 216 scriptFunction.flags, 217 scriptFunction.modifiers 218 ) 219 .setAnnotations([annotation('memo')]); 220 221 const modifiers: arkts.Es2pandaModifierFlags = isDecl 222 ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT 223 : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; 224 return arkts.factory.createMethodDefinition( 225 arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, 226 updateKey, 227 updateScriptFunction, 228 modifiers, 229 false 230 ); 231 } 232 233 /* 234 * add alias: <property.key.name> to @Provide annotation when no alias in @Provide({...}). 235 */ 236 static processNoAliasProvideVariable(property: arkts.ClassProperty): void { 237 let annotations: readonly arkts.AnnotationUsage[] = property.annotations; 238 if (annotations.length === 0) { 239 return; 240 } 241 const newAnnos: arkts.AnnotationUsage[] = annotations.map((anno: arkts.AnnotationUsage) => { 242 if ( 243 !!anno.expr && 244 arkts.isIdentifier(anno.expr) && 245 anno.expr.name === DecoratorNames.PROVIDE && 246 !hasPropertyInAnnotation(anno, 'alias') && 247 property.key && 248 arkts.isIdentifier(property.key) 249 ) { 250 return arkts.factory.update1AnnotationUsage(anno, anno.expr, [ 251 ...anno.properties, 252 factory.createAliasClassProperty(property.key), 253 ]); 254 } else { 255 return anno; 256 } 257 }); 258 property.setAnnotations(newAnnos); 259 } 260 261 /* 262 * create class property : `alias: <value>`. 263 */ 264 static createAliasClassProperty(value: arkts.Identifier): arkts.ClassProperty { 265 return arkts.factory.createClassProperty( 266 arkts.factory.createIdentifier('alias'), 267 arkts.factory.create1StringLiteral(value.name), 268 undefined, 269 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, 270 false 271 ); 272 } 273 274 /* 275 * add optional or definite modifier for class property needs initializing without assignment. 276 */ 277 static PreprocessClassPropertyModifier(st: arkts.AstNode): arkts.AstNode { 278 if (arkts.isClassProperty(st) && needDefiniteOrOptionalModifier(st)) { 279 if (st.typeAnnotation && hasNullOrUndefinedType(st.typeAnnotation)) { 280 st.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; 281 } else { 282 st.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DEFINITE; 283 } 284 } 285 return st; 286 } 287} 288