• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}