• 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, hasPropertyInAnnotation, hasNullOrUndefinedType } from './utils';
18import { annotation } from '../common/arkts-utils';
19import { DecoratorNames, needDefiniteOrOptionalModifier } from './property-translators/utils';
20
21export class factory {
22    /**
23     * create `instance: <typeName>` as identifier
24     */
25    static createInstanceIdentifier(typeName: string): arkts.Identifier {
26        return arkts.factory.createIdentifier(
27            BuilderLambdaNames.STYLE_ARROW_PARAM_NAME,
28            factory.createTypeReferenceFromString(typeName)
29        );
30    }
31
32    /**
33     * create `instance: <typeName>` as parameter
34     */
35    static createInstanceParameter(typeName: string): arkts.ETSParameterExpression {
36        return arkts.factory.createParameterDeclaration(factory.createInstanceIdentifier(typeName), undefined);
37    }
38
39    /**
40     * create `(instance: <typeName>) => void`
41     */
42    static createStyleLambdaFunctionType(typeName: string): arkts.ETSFunctionType {
43        return arkts.factory.createFunctionType(
44            arkts.FunctionSignature.createFunctionSignature(
45                undefined,
46                [factory.createInstanceParameter(typeName)],
47                factory.createTypeReferenceFromString(typeName),
48                false
49            ),
50            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW
51        );
52    }
53
54    /**
55     * create `style: ((instance: <typeName>) => void) | undefined` as identifier
56     */
57    static createStyleIdentifier(typeName: string): arkts.Identifier {
58        return arkts.factory.createIdentifier(
59            BuilderLambdaNames.STYLE_PARAM_NAME,
60            arkts.factory.createUnionType([
61                factory.createStyleLambdaFunctionType(typeName),
62                arkts.factory.createETSUndefinedType(),
63            ])
64        );
65    }
66
67    /**
68     * create `@memo() style: ((instance: <typeName>) => void) | undefined` as parameter
69     */
70    static createStyleParameter(typeName: string): arkts.ETSParameterExpression {
71        const styleParam: arkts.Identifier = factory.createStyleIdentifier(typeName);
72        const param = arkts.factory.createParameterDeclaration(styleParam, undefined);
73        param.annotations = [annotation('memo')];
74        return param;
75    }
76
77    /**
78     * create `initializers: <optionsName> | undefined` as identifier
79     */
80    static createInitializerOptionsIdentifier(optionsName: string): arkts.Identifier {
81        return arkts.factory.createIdentifier(
82            CustomComponentNames.COMPONENT_INITIALIZERS_NAME,
83            arkts.factory.createUnionType([
84                factory.createTypeReferenceFromString(optionsName),
85                arkts.factory.createETSUndefinedType(),
86            ])
87        );
88    }
89
90    /**
91     * create `initializers: <optionsName> | undefined` as parameter
92     */
93    static createInitializersOptionsParameter(optionsName: string): arkts.ETSParameterExpression {
94        return arkts.factory.createParameterDeclaration(
95            factory.createInitializerOptionsIdentifier(optionsName),
96            undefined
97        );
98    }
99
100    /**
101     * create `content: (() => void) | undefined` as identifier
102     */
103    static createContentIdentifier(): arkts.Identifier {
104        return arkts.factory.createIdentifier(
105            BuilderLambdaNames.CONTENT_PARAM_NAME,
106            arkts.factory.createUnionType([factory.createLambdaFunctionType(), arkts.factory.createETSUndefinedType()])
107        );
108    }
109
110    /**
111     * create `@memo() content: (() => void) | undefined` as parameter
112     */
113    static createContentParameter(): arkts.ETSParameterExpression {
114        const contentParam: arkts.Identifier = factory.createContentIdentifier();
115        const param = arkts.factory.createParameterDeclaration(contentParam, undefined);
116        param.annotations = [annotation('memo')];
117        return param;
118    }
119
120    /**
121     * create type from string
122     */
123    static createTypeReferenceFromString(name: string): arkts.TypeNode {
124        return arkts.factory.createTypeReference(
125            arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(name))
126        );
127    }
128
129    /**
130     * create `(<params>) => <returnType>`. If returnType is not given, then using `void`.
131     */
132    static createLambdaFunctionType(
133        params?: arkts.Expression[],
134        returnType?: arkts.TypeNode | undefined
135    ): arkts.ETSFunctionType {
136        return arkts.factory.createFunctionType(
137            arkts.FunctionSignature.createFunctionSignature(
138                undefined,
139                params ?? [],
140                returnType ?? arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
141                false
142            ),
143            arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW
144        );
145    }
146
147    /**
148     * create and insert `import { <imported> as <local> } from <source>` to the top of script's statements.
149     */
150    static createAndInsertImportDeclaration(
151        source: arkts.StringLiteral,
152        imported: arkts.Identifier,
153        local: arkts.Identifier,
154        importKind: arkts.Es2pandaImportKinds,
155        program: arkts.Program
156    ): void {
157        const importDecl: arkts.ETSImportDeclaration = arkts.factory.createImportDeclaration(
158            source,
159            [arkts.factory.createImportSpecifier(imported, local)],
160            importKind,
161            program,
162            arkts.Es2pandaImportFlags.IMPORT_FLAGS_NONE
163        );
164        arkts.importDeclarationInsert(importDecl, program);
165        return;
166    }
167
168    /*
169     * create `import { <imported> as <local> } ...`.
170     */
171    static createAdditionalImportSpecifier(imported: string, local: string): arkts.ImportSpecifier {
172        return arkts.factory.createImportSpecifier(
173            arkts.factory.createIdentifier(imported),
174            arkts.factory.createIdentifier(local)
175        );
176    }
177
178    /*
179     * create `constructor() {}`.
180     */
181    static createConstructorMethod(member: arkts.MethodDefinition): arkts.MethodDefinition {
182        return arkts.factory.createMethodDefinition(
183            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR,
184            member.name,
185            member.scriptFunction,
186            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR,
187            false
188        );
189    }
190
191    /*
192     * create `@memo() _build(<>)`.
193     */
194    static transformBuildMethodWithOriginBuild(
195        method: arkts.MethodDefinition,
196        typeName: string,
197        optionsName: string,
198        isDecl?: boolean
199    ): arkts.MethodDefinition {
200        const updateKey: arkts.Identifier = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_BUILD);
201
202        const scriptFunction: arkts.ScriptFunction = method.scriptFunction;
203        const updateScriptFunction = arkts.factory
204            .createScriptFunction(
205                scriptFunction.body,
206                arkts.FunctionSignature.createFunctionSignature(
207                    scriptFunction.typeParams,
208                    [
209                        factory.createStyleParameter(typeName),
210                        factory.createContentParameter(),
211                        factory.createInitializersOptionsParameter(optionsName),
212                    ],
213                    arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
214                    false
215                ),
216                scriptFunction.flags,
217                scriptFunction.modifiers
218            )
219            .setAnnotations([annotation('memo')]);
220
221        const modifiers: arkts.Es2pandaModifierFlags = isDecl
222            ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT
223            : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
224        return arkts.factory.createMethodDefinition(
225            arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
226            updateKey,
227            updateScriptFunction,
228            modifiers,
229            false
230        );
231    }
232
233    /*
234     * add alias: <property.key.name> to @Provide annotation when no alias in @Provide({...}).
235     */
236    static processNoAliasProvideVariable(property: arkts.ClassProperty): void {
237        let annotations: readonly arkts.AnnotationUsage[] = property.annotations;
238        if (annotations.length === 0) {
239            return;
240        }
241        const newAnnos: arkts.AnnotationUsage[] = annotations.map((anno: arkts.AnnotationUsage) => {
242            if (
243                !!anno.expr &&
244                arkts.isIdentifier(anno.expr) &&
245                anno.expr.name === DecoratorNames.PROVIDE &&
246                !hasPropertyInAnnotation(anno, 'alias') &&
247                property.key &&
248                arkts.isIdentifier(property.key)
249            ) {
250                return arkts.factory.update1AnnotationUsage(anno, anno.expr, [
251                    ...anno.properties,
252                    factory.createAliasClassProperty(property.key),
253                ]);
254            } else {
255                return anno;
256            }
257        });
258        property.setAnnotations(newAnnos);
259    }
260
261    /*
262     * create class property : `alias: <value>`.
263     */
264    static createAliasClassProperty(value: arkts.Identifier): arkts.ClassProperty {
265        return arkts.factory.createClassProperty(
266            arkts.factory.createIdentifier('alias'),
267            arkts.factory.create1StringLiteral(value.name),
268            undefined,
269            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
270            false
271        );
272    }
273
274    /*
275     * add optional or definite modifier for class property needs initializing without assignment.
276     */
277    static PreprocessClassPropertyModifier(st: arkts.AstNode): arkts.AstNode {
278        if (arkts.isClassProperty(st) && needDefiniteOrOptionalModifier(st)) {
279            if (st.typeAnnotation && hasNullOrUndefinedType(st.typeAnnotation)) {
280                st.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL;
281            } else {
282                st.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DEFINITE;
283            }
284        }
285        return st;
286    }
287}
288