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 { GenSymGenerator } from '../../common/gensym-generator'; 18import { factory as UIFactory } from '../ui-factory'; 19import { judgeIfAddWatchFunc } from './utils'; 20 21export class factory { 22 /** 23 * generate an substitution for optional expression ?., e.g. `{let _tmp = xxx; _tmp == null ? undefined : xxx}`. 24 * 25 * @param object item before ?.. 26 * @param key item after ?.. 27 */ 28 static createBlockStatementForOptionalExpression( 29 object: arkts.AstNode, 30 key: string, 31 isCall: boolean = false 32 ): arkts.Expression { 33 let id = GenSymGenerator.getInstance().id(key); 34 const statements: arkts.Statement[] = [ 35 factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object), 36 factory.generateTernaryExpression(id, key, isCall), 37 ]; 38 return arkts.factory.createBlockExpression(statements); 39 } 40 41 /** 42 * generate a variable declaration, e.g. `let <left> = <right>`; 43 * 44 * @param left left expression. 45 * @param right right expression. 46 */ 47 static generateLetVariableDecl(left: arkts.Identifier, right: arkts.AstNode): arkts.VariableDeclaration { 48 return arkts.factory.createVariableDeclaration( 49 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, 50 arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, 51 [ 52 arkts.factory.createVariableDeclarator( 53 arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, 54 left, 55 right 56 ), 57 ] 58 ); 59 } 60 61 /** 62 * generate a ternary expression, e.g. `<test> ? <consequent> : <alternate>`; 63 * 64 * @param testLeft the left hand of the test condition. 65 * @param key item after ?. 66 */ 67 static generateTernaryExpression( 68 testLeft: string, 69 key: string, 70 isCall: boolean = false 71 ): arkts.ExpressionStatement { 72 const test = arkts.factory.createBinaryExpression( 73 arkts.factory.createIdentifier(testLeft), 74 arkts.factory.createNullLiteral(), 75 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EQUAL 76 ); 77 const consequent: arkts.Expression = arkts.factory.createUndefinedLiteral(); 78 const alternate: arkts.MemberExpression = arkts.factory.createMemberExpression( 79 arkts.factory.createIdentifier(testLeft), 80 arkts.factory.createIdentifier(key), 81 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 82 false, 83 false 84 ); 85 return arkts.factory.createExpressionStatement( 86 arkts.factory.createConditionalExpression( 87 test, 88 consequent, 89 isCall ? arkts.factory.createCallExpression(alternate, undefined, undefined) : alternate 90 ) 91 ); 92 } 93 94 /** 95 * generate an substitution for two optional expression ?., e.g. a?.b?.c. 96 * 97 * @param node entry wrapper class declaration node. 98 */ 99 static createDoubleBlockStatementForOptionalExpression( 100 object: arkts.AstNode, 101 key1: string, 102 key2: string 103 ): arkts.Expression { 104 let id = GenSymGenerator.getInstance().id(key1); 105 let initial: arkts.Expression = factory.createBlockStatementForOptionalExpression(object, key1); 106 const statements: arkts.Statement[] = [ 107 factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), initial), 108 factory.generateTernaryExpression(id, key2), 109 ]; 110 return arkts.factory.createBlockExpression(statements); 111 } 112 113 /** 114 * generate an memberExpression with nonNull or optional, e.g. object.property, object?.property or object!.property 115 * 116 * @param object item before point. 117 * @param property item after point. 118 */ 119 static createNonNullOrOptionalMemberExpression( 120 object: string, 121 property: string, 122 optional: boolean, 123 nonNull: boolean 124 ): arkts.Expression { 125 const objectNode: arkts.Identifier = arkts.factory.createIdentifier(object); 126 return arkts.factory.createMemberExpression( 127 nonNull ? arkts.factory.createTSNonNullExpression(objectNode) : objectNode, 128 arkts.factory.createIdentifier(property), 129 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 130 false, 131 optional 132 ); 133 } 134 135 /* 136 * create `(<params>)<typeParams>: <returnType> => { <bodyStatementsList> }`. 137 */ 138 static createArrowFunctionWithParamsAndBody( 139 typeParams: arkts.TSTypeParameterDeclaration | undefined, 140 params: arkts.Expression[] | undefined, 141 returnType: arkts.TypeNode | undefined, 142 hasReceiver: boolean, 143 bodyStatementsList: arkts.Statement[] 144 ): arkts.ArrowFunctionExpression { 145 return arkts.factory.createArrowFunction( 146 arkts.factory.createScriptFunction( 147 arkts.BlockStatement.createBlockStatement(bodyStatementsList), 148 arkts.factory.createFunctionSignature(typeParams, params ? params : [], returnType, hasReceiver), 149 arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, 150 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE 151 ) 152 ); 153 } 154 155 /* 156 * create @Watch callback, e.g. (propertyName: string): void => {this.<callbackName>(propertyName)}. 157 */ 158 static createWatchCallback(callbackName: string): arkts.ArrowFunctionExpression { 159 return factory.createArrowFunctionWithParamsAndBody( 160 undefined, 161 [ 162 arkts.factory.createParameterDeclaration( 163 arkts.factory.createIdentifier('_', UIFactory.createTypeReferenceFromString('string')), 164 undefined 165 ), 166 ], 167 arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), 168 false, 169 [ 170 arkts.factory.createExpressionStatement( 171 arkts.factory.createCallExpression(factory.generateThisCall(callbackName), undefined, [ 172 arkts.factory.createIdentifier('_'), 173 ]) 174 ), 175 ] 176 ); 177 } 178 179 /* 180 * create this.<name> with optional or nonNullable. 181 */ 182 static generateThisCall(name: string, optional: boolean = false, nonNull: boolean = false): arkts.Expression { 183 const member: arkts.Expression = arkts.factory.createMemberExpression( 184 arkts.factory.createThisExpression(), 185 arkts.factory.createIdentifier(`${name}`), 186 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 187 false, 188 optional 189 ); 190 return nonNull ? arkts.factory.createTSNonNullExpression(member) : member; 191 } 192 193 /* 194 * create `initializers!.<newName>!.<getOrSet>(<args>)`. 195 */ 196 static createBackingGetOrSetCall( 197 newName: string, 198 getOrSet: string, 199 args: arkts.AstNode[] | undefined 200 ): arkts.CallExpression { 201 return arkts.factory.createCallExpression( 202 arkts.factory.createMemberExpression( 203 arkts.factory.createTSNonNullExpression( 204 factory.createNonNullOrOptionalMemberExpression('initializers', newName, false, true) 205 ), 206 arkts.factory.createIdentifier(getOrSet), 207 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 208 false, 209 false 210 ), 211 undefined, 212 args 213 ); 214 } 215 216 /* 217 * create `new <className><typeAnnotation>(<args>)`. 218 */ 219 static createNewDecoratedInstantiate( 220 className: string, 221 typeAnnotation: arkts.TypeNode | undefined, 222 args: arkts.Expression[] | undefined 223 ): arkts.ETSNewClassInstanceExpression { 224 return arkts.factory.createETSNewClassInstanceExpression( 225 arkts.factory.createTypeReference( 226 arkts.factory.createTypeReferencePart( 227 arkts.factory.createIdentifier(className), 228 arkts.factory.createTSTypeParameterInstantiation(typeAnnotation ? [typeAnnotation.clone()] : []) 229 ) 230 ), 231 args?.length ? args : [] 232 ); 233 } 234 235 /* 236 * create `this.addProvidedVar<number>(<originName>, <alias>, initializers?.<originalName> ?? <property.value>, <allowOverride>, watchFunc)`. 237 */ 238 static generateAddProvideVarCall( 239 originalName: string, 240 property: arkts.ClassProperty, 241 alias: string, 242 allowOverride: boolean = false 243 ): arkts.CallExpression { 244 const args: arkts.Expression[] = [ 245 arkts.factory.create1StringLiteral(originalName), 246 arkts.factory.create1StringLiteral(alias), 247 arkts.factory.createBinaryExpression( 248 factory.createBlockStatementForOptionalExpression( 249 arkts.factory.createIdentifier('initializers'), 250 originalName 251 ), 252 property.value ?? arkts.factory.createUndefinedLiteral(), 253 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING 254 ), 255 arkts.factory.createBooleanLiteral(allowOverride), 256 ]; 257 judgeIfAddWatchFunc(args, property); 258 return arkts.factory.createCallExpression( 259 arkts.factory.createMemberExpression( 260 arkts.factory.createThisExpression(), 261 arkts.factory.createIdentifier('addProvidedVar'), 262 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 263 false, 264 false 265 ), 266 property.typeAnnotation ? [property.typeAnnotation.clone()] : undefined, 267 args 268 ); 269 } 270 271 /* 272 * create `this.initConsume<number>(<originalName>, <alias>, watchFunc)`. 273 */ 274 static generateInitConsumeCall( 275 originalName: string, 276 property: arkts.ClassProperty, 277 alias: string 278 ): arkts.CallExpression { 279 const args: arkts.Expression[] = [ 280 arkts.factory.create1StringLiteral(originalName), 281 arkts.factory.create1StringLiteral(alias), 282 ]; 283 judgeIfAddWatchFunc(args, property); 284 return arkts.factory.createCallExpression( 285 arkts.factory.createMemberExpression( 286 arkts.factory.createThisExpression(), 287 arkts.factory.createIdentifier('initConsume'), 288 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 289 false, 290 false 291 ), 292 property.typeAnnotation ? [property.typeAnnotation.clone()] : undefined, 293 args 294 ); 295 } 296} 297