• 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 { getCustomComponentOptionsName } from './utils';
21import { InteropContext } from './component-transformer';
22import { annotation, backingField, isAnnotation } from '../common/arkts-utils';
23import { hasLink, processLink, processNormal } from './initstatevar';
24
25interface propertyInfo {
26    decorators: string[],
27    type: arkts.TypeNode,
28}
29
30export function createEmptyESValue(name: string): arkts.VariableDeclaration {
31    return arkts.factory.createVariableDeclaration(
32        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
33        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
34        [
35            arkts.factory.createVariableDeclarator(
36                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
37                arkts.factory.createIdentifier(name),
38                arkts.factory.createCallExpression(
39                    arkts.factory.createMemberExpression(
40                        arkts.factory.createIdentifier(InteroperAbilityNames.ESVALUE),
41                        arkts.factory.createIdentifier(InteroperAbilityNames.INITEMPTYOBJECT),
42                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
43                        false,
44                        false
45                    ),
46                    undefined,
47                    undefined
48                )
49            )
50        ]
51    );
52}
53
54export function getWrapValue(value: arkts.AstNode): arkts.AstNode {
55    return arkts.factory.createCallExpression(
56        arkts.factory.createMemberExpression(
57            arkts.factory.createIdentifier(InteroperAbilityNames.ESVALUE),
58            arkts.factory.createIdentifier(InteroperAbilityNames.WRAP),
59            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
60            false,
61            false
62        ),
63        undefined,
64        [value]
65    );
66}
67
68export function setPropertyESValue(name: string, key: string, wrapValue: arkts.AstNode): arkts.ExpressionStatement {
69    return arkts.factory.createExpressionStatement(
70        arkts.factory.createCallExpression(
71            arkts.factory.createMemberExpression(
72                arkts.factory.createIdentifier(name),
73                arkts.factory.createIdentifier(InteroperAbilityNames.SETPROPERTY),
74                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
75                false,
76                false
77            ),
78            undefined,
79            [
80                arkts.factory.createStringLiteral(key),
81                wrapValue
82            ]
83        )
84    );
85}
86
87export function getPropertyESValue(result: string, object: string, key: string): arkts.VariableDeclaration {
88    return arkts.factory.createVariableDeclaration(
89        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
90        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
91        [
92            arkts.factory.createVariableDeclarator(
93                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
94                arkts.factory.createIdentifier(result),
95                arkts.factory.createCallExpression(
96                    arkts.factory.createMemberExpression(
97                        arkts.factory.createIdentifier(object),
98                        arkts.factory.createIdentifier(InteroperAbilityNames.GETPROPERTY),
99                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
100                        false,
101                        false
102                    ),
103                    undefined,
104                    [arkts.factory.create1StringLiteral(key)]
105                )
106            )
107        ]
108    );
109}
110
111function initialArgs(args: arkts.ObjectExpression, varMap: Map<string, propertyInfo>): arkts.Statement[] {
112    const result: arkts.Statement[] = [
113        createEmptyESValue(InteroperAbilityNames.PARAM),
114        getPropertyESValue('createState', 'global', 'createStateVariable')
115    ];
116
117    const proxySet = new Set<string>();
118
119    for (const property of args.properties) {
120        if (!(property instanceof arkts.Property)) {
121            continue;
122        }
123        const key = property.key;
124        const value = property.value;
125        if (!(key instanceof arkts.Identifier)) {
126            throw Error('Error arguments in Legacy Component');
127        }
128        const name = key.name;
129        const decorators = varMap.get(name)?.decorators;
130        const type = varMap.get(name)?.type!;
131        if (decorators !== undefined && hasLink(decorators)) {
132            const initParam = processLink(key.name, value!, type, proxySet);
133            result.push(...initParam);
134        } else {
135            const initParam = processNormal(key.name, value!);
136            result.push(...initParam);
137        }
138    }
139    return result;
140}
141
142function instantiateComponent(params: arkts.AstNode[]): arkts.VariableDeclaration {
143    return arkts.factory.createVariableDeclaration(
144        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
145        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
146        [
147            arkts.factory.createVariableDeclarator(
148                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
149                arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT),
150                arkts.factory.createCallExpression(
151                    arkts.factory.createMemberExpression(
152                        arkts.factory.createIdentifier(InteroperAbilityNames.STRUCTOBJECT),
153                        arkts.factory.createIdentifier(InteroperAbilityNames.INSTANTIATE),
154                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
155                        false,
156                        false
157                    ),
158                    undefined,
159                    params
160                )
161            )
162        ]
163    );
164}
165
166function paramsLambdaDeclaration(name: string, args?: arkts.ObjectExpression): arkts.Statement[] {
167    const result = [];
168    result.push(
169        arkts.factory.createVariableDeclaration(
170            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
171            arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
172            [
173                arkts.factory.createVariableDeclarator(
174                    arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
175                    arkts.factory.createIdentifier(InteroperAbilityNames.PARAMSLAMBDA),
176                    arkts.factory.createArrowFunction(
177                        arkts.factory.createScriptFunction(
178                            arkts.factory.createBlock([arkts.factory.createReturnStatement(
179                                args ? args : arkts.ObjectExpression.createObjectExpression(
180                                    arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION,
181                                    [],
182                                    false
183                                ),
184                            )]),
185                            arkts.factory.createFunctionSignature(
186                                undefined,
187                                [],
188                                arkts.factory.createTypeReference(
189                                    arkts.factory.createTypeReferencePart(
190                                        arkts.factory.createIdentifier(getCustomComponentOptionsName(name))
191                                    )
192                                ),
193                                false
194                            ),
195                            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
196                            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
197                        )
198                    )
199                ),
200
201            ]
202        )
203    );
204    return result;
205}
206
207function createInitReturn(componentName: string): arkts.ReturnStatement {
208    return arkts.factory.createReturnStatement(
209        arkts.ObjectExpression.createObjectExpression(
210            arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION,
211            [
212                arkts.Property.createProperty(
213                    arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT),
214                    arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT)
215                ),
216                arkts.Property.createProperty(
217                    arkts.factory.createIdentifier('name'),
218                    arkts.factory.createStringLiteral(componentName)
219                )
220            ],
221            false
222        ),
223    );
224}
225
226function createExtraInfo(properties: string[], value: string[]): arkts.Statement[] {
227    const body: arkts.AstNode[] = [];
228    body.push(createEmptyESValue(InteroperAbilityNames.EXTRAINFO));
229    properties.forEach((prop, index) => {
230        const val = value[index];
231        body.push(setPropertyESValue(
232            InteroperAbilityNames.EXTRAINFO,
233            prop,
234            arkts.factory.createStringLiteral(val))
235        );
236    });
237    return body;
238}
239
240function createESParent(): arkts.Statement {
241    return arkts.factory.createVariableDeclaration(
242        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
243        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
244        [
245            arkts.factory.createVariableDeclarator(
246                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
247                arkts.factory.createIdentifier('esparent'),
248                getWrapValue(arkts.factory.createIdentifier(InteroperAbilityNames.PARENT))
249            )
250        ]
251    );
252}
253
254function createESUndefined(): arkts.Statement {
255    return arkts.factory.createVariableDeclaration(
256        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
257        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
258        [
259            arkts.factory.createVariableDeclarator(
260                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
261                arkts.factory.createIdentifier('esundefined'),
262                getWrapValue(arkts.factory.createUndefinedLiteral())
263            )
264        ]
265    );
266}
267
268function createESBlank(): arkts.Statement[] {
269    const body: arkts.Statement[] = [];
270    const blank = arkts.factory.createVariableDeclaration(
271        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
272        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
273        [
274            arkts.factory.createVariableDeclarator(
275                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
276                arkts.factory.createIdentifier('blank'),
277                arkts.factory.createArrowFunction(
278                    arkts.factory.createScriptFunction(
279                        arkts.factory.createBlock([]),
280                        arkts.factory.createFunctionSignature(
281                            undefined,
282                            [],
283                            undefined,
284                            false
285                        ),
286                        arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
287                        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
288                    )
289                )
290            )
291        ]
292    );
293    body.push(blank);
294    const asExpression = arkts.factory.createTSAsExpression(
295        arkts.factory.createIdentifier('blank'),
296        arkts.factory.createTypeReference(
297            arkts.factory.createTypeReferencePart(
298                arkts.factory.createIdentifier('object')
299            )
300        ),
301        false
302    );
303    const esblank = arkts.factory.createVariableDeclaration(
304        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
305        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
306        [
307            arkts.factory.createVariableDeclarator(
308                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
309                arkts.factory.createIdentifier('esblank'),
310                getWrapValue(asExpression)
311            )
312        ]
313    );
314    body.push(esblank);
315    return body;
316}
317
318function createGlobal(): arkts.Statement {
319    return arkts.factory.createVariableDeclaration(
320        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
321        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
322        [arkts.factory.createVariableDeclarator(
323            arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
324            arkts.factory.createIdentifier('global'),
325            arkts.factory.createCallExpression(
326                arkts.factory.createMemberExpression(
327                    arkts.factory.createIdentifier(InteroperAbilityNames.ESVALUE),
328                    arkts.factory.createIdentifier('getGlobal'),
329                    arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
330                    false,
331                    false
332                ),
333                undefined,
334                undefined
335            )
336        )]
337    );
338}
339
340function createELMTID(): arkts.Statement[] {
341    const body: arkts.Statement[] = [];
342    const viewStackProcessor = getPropertyESValue('viewStackProcessor', 'global', 'ViewStackProcessor');
343    body.push(viewStackProcessor);
344    const createId = getPropertyESValue('createId', 'viewStackProcessor', 'AllocateNewElmetIdForNextComponent');
345    body.push(createId);
346    const elmtId = arkts.factory.createVariableDeclaration(
347        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
348        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
349        [arkts.factory.createVariableDeclarator(
350            arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
351            arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID),
352            arkts.factory.createCallExpression(
353                arkts.factory.createMemberExpression(
354                    arkts.factory.createIdentifier('createId'),
355                    arkts.factory.createIdentifier('invoke'),
356                    arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
357                    false,
358                    false
359                ),
360                undefined,
361                undefined
362            )
363        )]
364    );
365    body.push(elmtId);
366    return body;
367}
368
369function createComponent(moduleName: string, className: string): arkts.Statement[] {
370    const body: arkts.Statement[] = [];
371    const module = arkts.factory.createVariableDeclaration(
372        arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
373        arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
374        [
375            arkts.factory.createVariableDeclarator(
376                arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
377                arkts.factory.createIdentifier(moduleName),
378                arkts.factory.createCallExpression(
379                    arkts.factory.createMemberExpression(
380                        arkts.factory.createIdentifier(InteroperAbilityNames.ESVALUE),
381                        arkts.factory.createIdentifier(InteroperAbilityNames.LOAD),
382                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
383                        false,
384                        false
385                    ),
386                    undefined,
387                    [arkts.factory.create1StringLiteral(InteroperAbilityNames.OHMURL)]
388                )
389            )
390        ]
391    );
392    body.push(module);
393    const structObject = getPropertyESValue('structObject', moduleName, className);
394    body.push(structObject);
395    const component = instantiateComponent(
396        [
397            arkts.factory.createIdentifier('esundefined'),
398            arkts.factory.createIdentifier(InteroperAbilityNames.PARAM),
399            arkts.factory.createIdentifier('esundefined'),
400            arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID),
401            arkts.factory.createIdentifier('esblank'),
402            arkts.factory.createIdentifier(InteroperAbilityNames.EXTRAINFO)
403        ]
404    );
405    body.push(component);
406    return body;
407}
408
409function invokeViewPUCreate(): arkts.Statement[] {
410    const body: arkts.Statement[] = [];
411    const createMethod = getPropertyESValue('create', 'structObject', 'create');
412    body.push(createMethod);
413    const viewPUCreate = arkts.factory.createExpressionStatement(
414        arkts.factory.createCallExpression(
415            arkts.factory.createMemberExpression(
416                arkts.factory.createIdentifier('create'),
417                arkts.factory.createIdentifier('invoke'),
418                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
419                false,
420                false
421            ),
422            undefined,
423            [
424                arkts.factory.createIdentifier('component')
425            ]
426        )
427    );
428    body.push(viewPUCreate);
429    return body;
430}
431
432function createWrapperBlock(context: InteropContext, varMap: Map<string, propertyInfo>): arkts.BlockStatement {
433    const className = context.className;
434    const path = context.path;
435    const args = context.arguments;
436    const index = path.indexOf('/');
437    if (index === -1) {
438        throw new Error('Error path of Legacy Component.');
439    }
440    const moduleName = path.substring(0, index);
441    const initialArgsStatement = args ? initialArgs(args, varMap) : [];
442    return arkts.factory.createBlock(
443        [
444            createGlobal(),
445            ...initialArgsStatement,
446            ...createExtraInfo(['page'], [path]),
447            createESUndefined(),
448            ...createESBlank(),
449            ...createELMTID(),
450            ...createComponent(moduleName, className),
451            ...invokeViewPUCreate(),
452            // ...paramsLambdaDeclaration(className, args),
453            // setPropertyESValue(
454            //     'component',
455            //     'paramsGenerator_',
456            //     arkts.factory.createIdentifier(InteroperAbilityNames.PARAMSLAMBDA)
457            // ),
458            createInitReturn(className)
459        ]
460    );
461}
462
463function createInitializer(context: InteropContext, varMap: Map<string, propertyInfo>): arkts.ArrowFunctionExpression {
464    const block = createWrapperBlock(context, varMap);
465    return arkts.factory.createArrowFunction(
466        arkts.factory.createScriptFunction(
467            block,
468            arkts.factory.createFunctionSignature(
469                undefined,
470                [],
471                undefined,
472                false,
473            ),
474            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
475            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
476        )
477    );
478}
479
480function createUpdater(esvalue: arkts.ETSTypeReference, varMap: Map<string, propertyInfo>): arkts.ArrowFunctionExpression {
481    return arkts.factory.createArrowFunction(
482        arkts.factory.createScriptFunction(
483            arkts.factory.createBlock(
484                [
485
486                ]
487            ),
488            arkts.factory.createFunctionSignature(
489                undefined,
490                [
491                    arkts.factory.createParameterDeclaration(
492                        arkts.factory.createIdentifier(InteroperAbilityNames.INSTANCE, esvalue),
493                        undefined,
494                    ),
495                ],
496                undefined,
497                false,
498            ),
499            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
500            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
501        )
502    );
503}
504
505function generateVarMap(node: arkts.Identifier): Map<string, propertyInfo> {
506    const decl = arkts.getDecl(node);
507    if (!(decl instanceof arkts.ClassDefinition)) {
508        throw Error("can't find legacy class declaration");
509    }
510    const result = new Map<string, propertyInfo>();
511    const definition = decl;
512    const body = definition.body;
513    body.forEach(node => {
514        if (node instanceof arkts.ClassProperty && node.key instanceof arkts.Identifier) {
515            const key = node.key.name;
516            const annotations = node.annotations;
517            const decorators: string[] = annotations.map(annotation => {
518                return (annotation.expr as arkts.Identifier).name;
519            });
520            const type: arkts.TypeNode = node.typeAnnotation!;
521            result.set(key, {decorators: decorators, type: type});
522        }
523    });
524    return result;
525}
526
527export function updateArkUICompatible(node: arkts.CallExpression): arkts.CallExpression {
528    const classInterop = (node.expression as arkts.MemberExpression).object as arkts.Identifier;
529    const className = classInterop.name;
530    const args = node.arguments;
531    const path = (args[0] as arkts.StringLiteral).str;
532    const line = args[1] instanceof arkts.UndefinedLiteral ? undefined : (args[1] as arkts.NumberLiteral).value;
533    const col = args[2] instanceof arkts.UndefinedLiteral ? undefined : (args[2] as arkts.NumberLiteral).value;
534    const options = args[3] instanceof arkts.UndefinedLiteral ? undefined : args[3] as arkts.ObjectExpression;
535    const context: InteropContext = {
536        className: className,
537        path: path,
538        line: line,
539        col: col,
540        arguments: options
541    };
542
543    const varMap: Map<string, propertyInfo> = generateVarMap(classInterop);
544    const esvalue = arkts.factory.createTypeReference(
545        arkts.factory.createTypeReferencePart(
546            arkts.factory.createIdentifier(InteroperAbilityNames.ESVALUE)
547        )
548    );
549    const initializer = createInitializer(context, varMap);
550    const updater = createUpdater(esvalue, varMap);
551    return arkts.factory.updateCallExpression(
552        node,
553        arkts.factory.createIdentifier(InteroperAbilityNames.ARKUICOMPATIBLE),
554        undefined,
555        [
556            initializer,
557            updater,
558        ]
559    );
560}
561
562
563function generateStructInfo(context: InteropContext): arkts.AstNode[] {
564    const result: arkts.AstNode[] = [
565        arkts.factory.createStringLiteral(context.path),
566        context.line ? arkts.factory.createIdentifier(context.line.toString()) : arkts.factory.createUndefinedLiteral(),
567        context.col ? arkts.factory.createIdentifier(context.col.toString()) : arkts.factory.createUndefinedLiteral(),
568        context.arguments ?? arkts.factory.createUndefinedLiteral()
569    ];
570    return result;
571
572}
573
574export function generateTempCallFunction(context: InteropContext): arkts.CallExpression {
575    return arkts.factory.createCallExpression(
576        arkts.factory.createMemberExpression(
577            arkts.factory.createIdentifier(context.className),
578            arkts.factory.createIdentifier('instantiate_Interop'),
579            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
580            false,
581            false
582        ),
583        undefined,
584        generateStructInfo(context)
585    );
586}
587
588export function isArkUICompatible(node: arkts.AstNode): boolean {
589    if (node instanceof arkts.CallExpression && node.expression instanceof arkts.MemberExpression &&
590        node.expression.property instanceof arkts.Identifier &&
591        node.expression.property.name === 'instantiate_Interop') {
592        return true;
593    }
594    return false;
595}