1/* 2 * Copyright (c) 2022-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 16 17 18import * as arkts from '@koalaui/libarkts'; 19import { InteroperAbilityNames } from '../common/predefines'; 20import { annotation, backingField, isAnnotation } from '../common/arkts-utils'; 21import { getPropertyESValue, getWrapValue, setPropertyESValue } from './interop'; 22 23 24export function processNormal(keyName: string, value: arkts.AstNode): arkts.Statement[] { 25 const result: arkts.Statement[] = []; 26 const setProperty = setPropertyESValue( 27 InteroperAbilityNames.PARAM, 28 keyName, 29 getWrapValue(value) 30 ); 31 result.push(setProperty); 32 return result; 33} 34 35export function createVariableLet(varName: string, expression: arkts.AstNode): arkts.VariableDeclaration { 36 return arkts.factory.createVariableDeclaration( 37 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, 38 arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, 39 [arkts.factory.createVariableDeclarator( 40 arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, 41 arkts.factory.createIdentifier(varName), 42 expression 43 )] 44 ); 45} 46export function setValueCallback(name: string, type: arkts.TypeNode, block: arkts.BlockStatement): arkts.AstNode { 47 return createVariableLet(name, 48 arkts.factory.createArrowFunction( 49 arkts.factory.createScriptFunction( 50 block, 51 arkts.factory.createFunctionSignature( 52 undefined, 53 [ 54 arkts.factory.createParameterDeclaration( 55 arkts.factory.createIdentifier('value', type), 56 undefined, 57 ), 58 ], 59 undefined, 60 false 61 ), 62 arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, 63 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, 64 ) 65 ) 66 ); 67} 68 69function createProxyBlock(varName: string): arkts.BlockStatement { 70 return arkts.factory.createBlock( 71 [ 72 arkts.factory.createExpressionStatement( 73 arkts.factory.createAssignmentExpression( 74 arkts.factory.createMemberExpression( 75 arkts.factory.createThisExpression(), 76 arkts.factory.createIdentifier(varName), 77 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 78 false, 79 false 80 ), 81 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, 82 arkts.factory.createIdentifier('value') 83 ) 84 ) 85 ] 86 ); 87} 88 89export function setCallbackForProxy(varName: string, type: arkts.TypeNode): arkts.Statement[] { 90 const createCallback = setValueCallback(addStatePrefix(varName, 'SetSource'), type, createProxyBlock(varName)); 91 const createProxyState = createVariableLet(addStatePrefix(varName, 'ProxyState'), 92 arkts.factory.createCallExpression( 93 arkts.factory.createMemberExpression( 94 arkts.factory.createIdentifier('createState'), 95 arkts.factory.createIdentifier('invoke'), 96 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 97 false, 98 false 99 ), 100 undefined, 101 [ 102 getWrapValue( 103 arkts.factory.createMemberExpression( 104 arkts.factory.createThisExpression(), 105 arkts.factory.createIdentifier(varName), 106 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 107 false, 108 false 109 ) 110 ), 111 getWrapValue(arkts.factory.createIdentifier(addStatePrefix(varName, 'SetSource'))) 112 ] 113 ) 114 ); 115 const setProxy = arkts.factory.createExpressionStatement( 116 arkts.factory.createCallExpression( 117 arkts.factory.createMemberExpression( 118 arkts.factory.createTSNonNullExpression( 119 arkts.factory.createMemberExpression( 120 arkts.factory.createThisExpression(), 121 arkts.factory.createIdentifier(backingField(varName)), 122 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 123 false, 124 false 125 ) 126 ), 127 arkts.factory.createIdentifier('setProxy'), 128 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 129 false, 130 false 131 ), 132 undefined, 133 [arkts.factory.createIdentifier(addStatePrefix(varName, 'ProxyState'))], 134 ) 135 ); 136 return [createCallback, createProxyState, setProxy]; 137} 138 139function createSourceBlock(varName: string): arkts.BlockStatement { 140 return arkts.factory.createBlock( 141 [ 142 arkts.factory.createExpressionStatement( 143 arkts.factory.createCallExpression( 144 arkts.factory.createMemberExpression( 145 arkts.factory.createIdentifier(addStatePrefix(varName, 'ProxyState')), 146 arkts.factory.createIdentifier('invokeMethod'), 147 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 148 false, 149 false 150 ), 151 undefined, 152 [ 153 arkts.factory.createStringLiteral('set'), 154 getWrapValue( 155 arkts.factory.createIdentifier('value') 156 ) 157 ] 158 ) 159 ) 160 ] 161 ); 162} 163 164function createNotifyBlock(varName: string): arkts.BlockStatement { 165 return arkts.factory.createBlock( 166 [ 167 arkts.factory.createExpressionStatement( 168 arkts.factory.createCallExpression( 169 arkts.factory.createMemberExpression( 170 arkts.factory.createIdentifier(addStatePrefix(varName, 'ProxyState')), 171 arkts.factory.createIdentifier('invokeMethod'), 172 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 173 false, 174 false 175 ), 176 undefined, 177 [ 178 arkts.factory.createStringLiteral('notifyPropertyHasChangedPU') 179 ] 180 ) 181 ) 182 ] 183 ); 184} 185 186function setNotifyForSource(varName: string): arkts.Statement[] { 187 const block = createNotifyBlock(varName); 188 const createCallback = createVariableLet(addStatePrefix(varName, 'NotifyCallback'), 189 arkts.factory.createArrowFunction( 190 arkts.factory.createScriptFunction( 191 block, 192 arkts.factory.createFunctionSignature( 193 undefined, 194 [ 195 arkts.factory.createParameterDeclaration( 196 arkts.factory.createIdentifier('propertyName', 197 arkts.factory.createTypeReference( 198 arkts.factory.createTypeReferencePart( 199 arkts.factory.createIdentifier('string') 200 ) 201 ) 202 ), 203 undefined, 204 ), 205 ], 206 undefined, 207 false 208 ), 209 arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, 210 arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, 211 ) 212 ) 213 ); 214 const setCallback = arkts.factory.createExpressionStatement( 215 arkts.factory.createCallExpression( 216 arkts.factory.createMemberExpression( 217 arkts.factory.createTSNonNullExpression( 218 arkts.factory.createMemberExpression( 219 arkts.factory.createThisExpression(), 220 arkts.factory.createIdentifier(backingField(varName)), 221 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 222 false, 223 false 224 ) 225 ), 226 arkts.factory.createIdentifier('setNotifyCallback'), 227 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 228 false, 229 false 230 ), 231 undefined, 232 [arkts.factory.createIdentifier(addStatePrefix(varName, 'NotifyCallback'))], 233 ) 234 ); 235 return [createCallback, setCallback]; 236} 237 238export function setCallbackForSource(varName: string, type: arkts.TypeNode): arkts.Statement[] { 239 const createCallback = setValueCallback(addStatePrefix(varName, 'SetProxy'), type, createSourceBlock(varName)); 240 const setFunc = arkts.factory.createExpressionStatement( 241 arkts.factory.createAssignmentExpression( 242 arkts.factory.createMemberExpression( 243 arkts.factory.createTSNonNullExpression( 244 arkts.factory.createMemberExpression( 245 arkts.factory.createThisExpression(), 246 arkts.factory.createIdentifier(backingField(varName)), 247 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 248 false, 249 false 250 ) 251 ), 252 arkts.factory.createIdentifier('setProxyValue'), 253 arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, 254 false, 255 false 256 ), 257 arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, 258 arkts.factory.createIdentifier(addStatePrefix(varName, 'SetProxy')) 259 ) 260 ); 261 const setNotify = setNotifyForSource(varName); 262 return [createCallback, setFunc, ...setNotify]; 263} 264 265export function processLink(keyName: string, value: arkts.AstNode, type: arkts.TypeNode, proxySet: Set<string>): arkts.Statement[] { 266 const varName = ((value as arkts.MemberExpression).property as arkts.Identifier).name; 267 const result: arkts.Statement[] = []; 268 if (!proxySet.has(varName)) { 269 proxySet.add(varName); 270 const setProxy = setCallbackForProxy(varName, type); 271 result.push(...setProxy); 272 const setSource = setCallbackForSource(varName, type); 273 result.push(...setSource); 274 } 275 const setParam = setPropertyESValue( 276 'param', 277 keyName, 278 arkts.factory.createIdentifier(addStatePrefix(varName, 'ProxyState')) 279 ); 280 result.push(setParam); 281 return result; 282} 283 284export function hasLink(decorators: string[]): boolean { 285 return decorators.some(decorator => decorator === 'Link'); 286} 287 288function addStatePrefix(stateVarName: string, name: string): string { 289 return `${stateVarName}_${name}`; 290}