• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { BuilderLambdaNames, CustomComponentNames, Dollars } from '../utils';
18import { factory as uiFactory } from '../ui-factory';
19import { annotation } from '../../common/arkts-utils';
20
21export class factory {
22    /*
23     * create `constructor() {}`.
24     */
25    static createConstructorMethod(member: arkts.MethodDefinition): arkts.MethodDefinition {
26        return arkts.factory.createMethodDefinition(
27            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR,
28            member.name,
29            member.scriptFunction,
30            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR,
31            false
32        );
33    }
34
35    /*
36     * create _build method.
37     */
38    static transformBuildMethodWithOriginBuild(
39        method: arkts.MethodDefinition,
40        typeName: string,
41        optionsName: string,
42        isDecl?: boolean
43    ): arkts.MethodDefinition {
44        const updateKey: arkts.Identifier = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_BUILD);
45
46        const scriptFunction: arkts.ScriptFunction = method.scriptFunction;
47        const updateScriptFunction = arkts.factory
48            .createScriptFunction(
49                scriptFunction.body,
50                arkts.FunctionSignature.createFunctionSignature(
51                    scriptFunction.typeParams,
52                    [
53                        uiFactory.createStyleParameter(typeName),
54                        uiFactory.createContentParameter(),
55                        uiFactory.createInitializersOptionsParameter(optionsName),
56                    ],
57                    arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
58                    false
59                ),
60                scriptFunction.flags,
61                scriptFunction.modifiers
62            )
63            .setAnnotations([annotation('memo')]);
64
65        const modifiers: arkts.Es2pandaModifierFlags = isDecl
66            ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT
67            : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
68        return arkts.factory.createMethodDefinition(
69            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
70            updateKey,
71            updateScriptFunction,
72            modifiers,
73            false
74        );
75    }
76
77    /*
78     * generate _r(<newArgs>) or _rawfile(<newArgs>).
79     */
80    static generateTransformedResource(
81        resourceNode: arkts.CallExpression,
82        newArgs: arkts.AstNode[]
83    ): arkts.CallExpression {
84        const transformedKey: string =
85            resourceNode.expression.dumpSrc() === Dollars.DOLLAR_RESOURCE ? '_r' : '_rawfile';
86        return arkts.factory.updateCallExpression(
87            resourceNode,
88            arkts.factory.createIdentifier(transformedKey),
89            resourceNode.typeArguments,
90            newArgs
91        );
92    }
93
94    /*
95     * create __initializeStruct method.
96     */
97    static createInitializeStruct(
98        structInfo: arkts.StructInfo,
99        optionsTypeName: string,
100        isDecl?: boolean
101    ): arkts.MethodDefinition {
102        const updateKey: arkts.Identifier = arkts.factory.createIdentifier(
103            CustomComponentNames.COMPONENT_INITIALIZE_STRUCT
104        );
105
106        let body: arkts.BlockStatement | undefined;
107        let modifiers: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT;
108        if (!isDecl) {
109            body = arkts.factory.createBlock(structInfo.initializeBody);
110            modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
111        }
112        const scriptFunction: arkts.ScriptFunction = arkts.factory
113            .createScriptFunction(
114                body,
115                arkts.FunctionSignature.createFunctionSignature(
116                    undefined,
117                    [uiFactory.createInitializersOptionsParameter(optionsTypeName), uiFactory.createContentParameter()],
118                    arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
119                    false
120                ),
121                arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
122                modifiers
123            )
124            .setIdent(updateKey);
125
126        return arkts.factory.createMethodDefinition(
127            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
128            updateKey,
129            scriptFunction,
130            modifiers,
131            false
132        );
133    }
134
135    /*
136     * create __updateStruct method.
137     */
138    static createUpdateStruct(
139        structInfo: arkts.StructInfo,
140        optionsTypeName: string,
141        isDecl?: boolean
142    ): arkts.MethodDefinition {
143        const updateKey: arkts.Identifier = arkts.factory.createIdentifier(
144            CustomComponentNames.COMPONENT_UPDATE_STRUCT
145        );
146
147        let body: arkts.BlockStatement | undefined;
148        let modifiers: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT;
149        if (!isDecl) {
150            body = arkts.factory.createBlock(structInfo.updateBody);
151            modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
152        }
153
154        const scriptFunction: arkts.ScriptFunction = arkts.factory
155            .createScriptFunction(
156                body,
157                arkts.FunctionSignature.createFunctionSignature(
158                    undefined,
159                    [uiFactory.createInitializersOptionsParameter(optionsTypeName)],
160                    arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
161                    false
162                ),
163                arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
164                modifiers
165            )
166            .setIdent(updateKey);
167
168        return arkts.factory.createMethodDefinition(
169            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
170            updateKey,
171            scriptFunction,
172            modifiers,
173            false
174        );
175    }
176
177    /*
178     * create __toRecord method when the component is decorated with @Reusable.
179     */
180    static toRecord(optionsTypeName: string, toRecordBody: arkts.Property[]): arkts.MethodDefinition {
181        const paramsCasted = factory.generateParamsCasted(optionsTypeName);
182        const returnRecord = arkts.factory.createReturnStatement(
183            arkts.ObjectExpression.createObjectExpression(
184                arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION,
185                toRecordBody,
186                false
187            )
188        );
189        const body: arkts.BlockStatement = arkts.factory.createBlock([paramsCasted, returnRecord]);
190
191        const params = arkts.ETSParameterExpression.create(
192            arkts.factory.createIdentifier('params', factory.generateTypeReferenceWithTypeName('Object')),
193            undefined
194        );
195
196        const toRecordScriptFunction = arkts.factory.createScriptFunction(
197            body,
198            arkts.FunctionSignature.createFunctionSignature(undefined, [params], factory.generateTypeRecord(), false),
199            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
200            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC
201        );
202
203        return arkts.factory.createMethodDefinition(
204            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR,
205            arkts.factory.createIdentifier('__toRecord'),
206            toRecordScriptFunction,
207            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OVERRIDE,
208            false
209        );
210    }
211
212    /*
213     * generate `const paramsCasted = (params as <optionsTypeName>)`.
214     */
215    static generateParamsCasted(optionsTypeName: string): arkts.VariableDeclaration {
216        return arkts.factory.createVariableDeclaration(
217            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
218            arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST,
219            [
220                arkts.factory.createVariableDeclarator(
221                    arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_CONST,
222                    arkts.factory.createIdentifier('paramsCasted'),
223                    arkts.TSAsExpression.createTSAsExpression(
224                        arkts.factory.createIdentifier('params'),
225                        factory.generateTypeReferenceWithTypeName(optionsTypeName),
226                        false
227                    )
228                ),
229            ]
230        );
231    }
232
233    /*
234     * generate Record<string, Object> type.
235     */
236    static generateTypeRecord(): arkts.ETSTypeReference {
237        return arkts.factory.createTypeReference(
238            arkts.factory.createTypeReferencePart(
239                arkts.factory.createIdentifier('Record'),
240                arkts.factory.createTSTypeParameterInstantiation([
241                    factory.generateTypeReferenceWithTypeName('string'),
242                    factory.generateTypeReferenceWithTypeName('Object'),
243                ])
244            )
245        );
246    }
247
248    /*
249     * create type reference with type name, e.g. number.
250     */
251    static generateTypeReferenceWithTypeName(typeName: string): arkts.ETSTypeReference {
252        return arkts.factory.createTypeReference(
253            arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(typeName))
254        );
255    }
256
257    /*
258     * create type reference with type name, e.g. number.
259     */
260    static updateCustomComponentClass(
261        definition: arkts.ClassDefinition,
262        members: arkts.AstNode[]
263    ): arkts.ClassDefinition {
264        return arkts.factory.updateClassDefinition(
265            definition,
266            definition.ident,
267            definition.typeParams,
268            definition.superTypeParams,
269            definition.implements,
270            undefined,
271            definition.super,
272            members,
273            definition.modifiers,
274            arkts.classDefinitionFlags(definition)
275        );
276    }
277
278    /*
279     * add headers for animation in CommonMethod
280     */
281    static modifyExternalComponentCommon(node: arkts.TSInterfaceDeclaration): arkts.AstNode {
282        const animationStart = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_START);
283        const animationStop = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_STOP);
284        const updatedBody = arkts.factory.updateInterfaceBody(node.body!, [
285            animationStart,
286            animationStop,
287            ...node.body!.body,
288        ]);
289        return arkts.factory.updateInterfaceDeclaration(
290            node,
291            node.extends,
292            node.id,
293            node.typeParams,
294            updatedBody,
295            node.isStatic,
296            node.isFromExternal
297        );
298    }
299
300    /*
301     * generate animationStart(...) and animationStop(...)
302     */
303    static createAnimationMethod(key: string): arkts.MethodDefinition {
304        const aniparams: arkts.Expression[] = [
305            arkts.factory.createParameterDeclaration(
306                arkts.factory.createIdentifier(
307                    'value',
308                    arkts.factory.createUnionType(
309                        [
310                            arkts.factory.createTypeReference(
311                                arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('AnimateParam'))
312                            ),
313                            arkts.factory.createETSUndefinedType()
314                        ]
315                    )
316                ),
317                undefined
318            ),
319        ];
320        const aniFuncExpr = arkts.factory.createScriptFunction(
321            undefined,
322            arkts.factory.createFunctionSignature(undefined, aniparams, arkts.TSThisType.createTSThisType(), false),
323            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
324            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC
325        );
326        return arkts.factory.createMethodDefinition(
327            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
328            arkts.factory.createIdentifier(key),
329            aniFuncExpr,
330            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC,
331            false
332        );
333    }
334
335    /*
336     * generate XComponent(..., packageInfo: string, ...)
337     */
338    static modifyXcomponent(node: arkts.ScriptFunction): arkts.ScriptFunction {
339        const info = arkts.factory.createParameterDeclaration(
340            arkts.factory.createIdentifier(
341                'packageInfo',
342                arkts.factory.createTypeReference(
343                    arkts.factory.createTypeReferencePart(
344                        arkts.factory.createIdentifier('string')
345                    )
346                )
347            ),
348            undefined
349        );
350        return arkts.factory.updateScriptFunction(
351            node,
352            node.body,
353            arkts.factory.createFunctionSignature(
354                node.typeParams,
355                [...node.params.slice(0, 2), info, ...node.params.slice(2)],
356                node.returnTypeAnnotation,
357                false
358            ),
359            node.flags,
360            node.modifiers
361        );
362    }
363
364    /*
365     * transform ExternalSource headers
366     */
367    static transformExternalSource(externalSourceName: string, node: arkts.AstNode): arkts.AstNode {
368        if (
369            externalSourceName === 'arkui.component.common' &&
370            arkts.isTSInterfaceDeclaration(node) &&
371            !!node.id &&
372            node.id.name === 'CommonMethod'
373        ) {
374            return factory.modifyExternalComponentCommon(node);
375        } else if (
376            externalSourceName === 'arkui.component.xcomponent' &&
377            arkts.isScriptFunction(node) &&
378            !!node.id &&
379            node.id.name === 'XComponent'
380        ) {
381            return factory.modifyXcomponent(node);
382        }
383        return node;
384    }
385}
386