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'; 17 18import { 19 generateToRecord, 20 createGetter, 21 createSetter2, 22 generateGetOrSetCall, 23 generateThisBacking, 24 judgeIfAddWatchFunc, 25} from './utils'; 26import { PropertyTranslator } from './base'; 27import { GetterSetter, InitializerConstructor } from './types'; 28import { backingField, expectName } from '../../common/arkts-utils'; 29import { createOptionalClassProperty } from '../utils'; 30import { factory } from './factory'; 31 32export class PropTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { 33 translateMember(): arkts.AstNode[] { 34 const originalName: string = expectName(this.property.key); 35 const newName: string = backingField(originalName); 36 37 this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... 38 return this.translateWithoutInitializer(newName, originalName); 39 } 40 41 cacheTranslatedInitializer(newName: string, originalName: string): void { 42 const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); 43 const mutableThis: arkts.Expression = generateThisBacking(newName); 44 const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); 45 const updateStruct: arkts.AstNode = this.generateUpdateStruct(mutableThis, originalName); 46 currentStructInfo.initializeBody.push(initializeStruct); 47 currentStructInfo.updateBody.push(updateStruct); 48 if (currentStructInfo.isReusable) { 49 const toRecord = generateToRecord(newName, originalName); 50 currentStructInfo.toRecordBody.push(toRecord); 51 } 52 arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); 53 } 54 55 translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { 56 const field: arkts.ClassProperty = createOptionalClassProperty( 57 newName, 58 this.property, 59 'PropDecoratedVariable', 60 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE 61 ); 62 const thisValue: arkts.Expression = generateThisBacking(newName, false, true); 63 const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, 'get'); 64 const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( 65 generateGetOrSetCall(thisValue, 'set') 66 ); 67 const getter: arkts.MethodDefinition = this.translateGetter( 68 originalName, 69 this.property.typeAnnotation, 70 thisGet 71 ); 72 const setter: arkts.MethodDefinition = this.translateSetter( 73 originalName, 74 this.property.typeAnnotation, 75 thisSet 76 ); 77 78 return [field, getter, setter]; 79 } 80 81 translateGetter( 82 originalName: string, 83 typeAnnotation: arkts.TypeNode | undefined, 84 returnValue: arkts.Expression 85 ): arkts.MethodDefinition { 86 return createGetter(originalName, typeAnnotation, returnValue); 87 } 88 89 translateSetter( 90 originalName: string, 91 typeAnnotation: arkts.TypeNode | undefined, 92 statement: arkts.AstNode 93 ): arkts.MethodDefinition { 94 return createSetter2(originalName, typeAnnotation, statement); 95 } 96 97 generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { 98 const binaryItem = arkts.factory.createBinaryExpression( 99 factory.createBlockStatementForOptionalExpression( 100 arkts.factory.createIdentifier('initializers'), 101 originalName 102 ), 103 this.property.value ?? arkts.factory.createUndefinedLiteral(), 104 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING 105 ); 106 const args: arkts.Expression[] = [ 107 arkts.factory.create1StringLiteral(originalName), 108 this.property.value 109 ? binaryItem 110 : arkts.factory.createTSAsExpression( 111 factory.createNonNullOrOptionalMemberExpression('initializers', originalName, false, true), 112 this.property.typeAnnotation ? this.property.typeAnnotation.clone() : undefined, 113 false 114 ), 115 ]; 116 judgeIfAddWatchFunc(args, this.property); 117 const right = arkts.factory.createETSNewClassInstanceExpression( 118 arkts.factory.createTypeReference( 119 arkts.factory.createTypeReferencePart( 120 arkts.factory.createIdentifier('PropDecoratedVariable'), 121 arkts.factory.createTSTypeParameterInstantiation( 122 this.property.typeAnnotation ? [this.property.typeAnnotation] : [] 123 ) 124 ) 125 ), 126 args 127 ); 128 const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( 129 generateThisBacking(newName), 130 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, 131 right 132 ); 133 return arkts.factory.createExpressionStatement(assign); 134 } 135 136 generateUpdateStruct(mutableThis: arkts.Expression, originalName: string): arkts.AstNode { 137 const binaryItem = arkts.factory.createBinaryExpression( 138 factory.createBlockStatementForOptionalExpression( 139 arkts.factory.createIdentifier('initializers'), 140 originalName 141 ), 142 arkts.factory.createUndefinedLiteral(), 143 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL 144 ); 145 const member: arkts.MemberExpression = arkts.factory.createMemberExpression( 146 arkts.factory.createTSNonNullExpression(mutableThis), 147 arkts.factory.createIdentifier('update'), 148 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 149 false, 150 false 151 ); 152 return arkts.factory.createIfStatement( 153 binaryItem, 154 arkts.factory.createBlock([ 155 arkts.factory.createExpressionStatement( 156 arkts.factory.createCallExpression(member, undefined, [ 157 arkts.factory.createTSAsExpression( 158 factory.createNonNullOrOptionalMemberExpression('initializers', originalName, false, true), 159 this.property.typeAnnotation ? this.property.typeAnnotation.clone() : undefined, 160 false 161 ), 162 ]) 163 ), 164 ]) 165 ); 166 } 167} 168