• 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 { GenSymGenerator } from '../../common/gensym-generator';
18import { factory as UIFactory } from '../ui-factory';
19import { judgeIfAddWatchFunc } from './utils';
20
21export class factory {
22    /**
23     * generate an substitution for optional expression ?., e.g. `{let _tmp = xxx; _tmp == null ? undefined : xxx}`.
24     *
25     * @param object item before ?..
26     * @param key item after ?..
27     */
28    static createBlockStatementForOptionalExpression(
29        object: arkts.AstNode,
30        key: string,
31        isCall: boolean = false
32    ): arkts.Expression {
33        let id = GenSymGenerator.getInstance().id(key);
34        const statements: arkts.Statement[] = [
35            factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object),
36            factory.generateTernaryExpression(id, key, isCall),
37        ];
38        return arkts.factory.createBlockExpression(statements);
39    }
40
41    /**
42     * generate a variable declaration, e.g. `let <left> = <right>`;
43     *
44     * @param left left expression.
45     * @param right right expression.
46     */
47    static generateLetVariableDecl(left: arkts.Identifier, right: arkts.AstNode): arkts.VariableDeclaration {
48        return arkts.factory.createVariableDeclaration(
49            arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
50            arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET,
51            [
52                arkts.factory.createVariableDeclarator(
53                    arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET,
54                    left,
55                    right
56                ),
57            ]
58        );
59    }
60
61    /**
62     * generate a ternary expression, e.g. `<test> ? <consequent> : <alternate>`;
63     *
64     * @param testLeft the left hand of the test condition.
65     * @param key item after ?.
66     */
67    static generateTernaryExpression(
68        testLeft: string,
69        key: string,
70        isCall: boolean = false
71    ): arkts.ExpressionStatement {
72        const test = arkts.factory.createBinaryExpression(
73            arkts.factory.createIdentifier(testLeft),
74            arkts.factory.createNullLiteral(),
75            arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EQUAL
76        );
77        const consequent: arkts.Expression = arkts.factory.createUndefinedLiteral();
78        const alternate: arkts.MemberExpression = arkts.factory.createMemberExpression(
79            arkts.factory.createIdentifier(testLeft),
80            arkts.factory.createIdentifier(key),
81            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
82            false,
83            false
84        );
85        return arkts.factory.createExpressionStatement(
86            arkts.factory.createConditionalExpression(
87                test,
88                consequent,
89                isCall ? arkts.factory.createCallExpression(alternate, undefined, undefined) : alternate
90            )
91        );
92    }
93
94    /**
95     * generate an substitution for two optional expression ?., e.g. a?.b?.c.
96     *
97     * @param node entry wrapper class declaration node.
98     */
99    static createDoubleBlockStatementForOptionalExpression(
100        object: arkts.AstNode,
101        key1: string,
102        key2: string
103    ): arkts.Expression {
104        let id = GenSymGenerator.getInstance().id(key1);
105        let initial: arkts.Expression = factory.createBlockStatementForOptionalExpression(object, key1);
106        const statements: arkts.Statement[] = [
107            factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), initial),
108            factory.generateTernaryExpression(id, key2),
109        ];
110        return arkts.factory.createBlockExpression(statements);
111    }
112
113    /**
114     * generate an memberExpression with nonNull or optional, e.g. object.property, object?.property or object!.property
115     *
116     * @param object item before point.
117     * @param property item after point.
118     */
119    static createNonNullOrOptionalMemberExpression(
120        object: string,
121        property: string,
122        optional: boolean,
123        nonNull: boolean
124    ): arkts.Expression {
125        const objectNode: arkts.Identifier = arkts.factory.createIdentifier(object);
126        return arkts.factory.createMemberExpression(
127            nonNull ? arkts.factory.createTSNonNullExpression(objectNode) : objectNode,
128            arkts.factory.createIdentifier(property),
129            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
130            false,
131            optional
132        );
133    }
134
135    /*
136     * create `(<params>)<typeParams>: <returnType> => { <bodyStatementsList> }`.
137     */
138    static createArrowFunctionWithParamsAndBody(
139        typeParams: arkts.TSTypeParameterDeclaration | undefined,
140        params: arkts.Expression[] | undefined,
141        returnType: arkts.TypeNode | undefined,
142        hasReceiver: boolean,
143        bodyStatementsList: arkts.Statement[]
144    ): arkts.ArrowFunctionExpression {
145        return arkts.factory.createArrowFunction(
146            arkts.factory.createScriptFunction(
147                arkts.BlockStatement.createBlockStatement(bodyStatementsList),
148                arkts.factory.createFunctionSignature(typeParams, params ? params : [], returnType, hasReceiver),
149                arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
150                arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE
151            )
152        );
153    }
154
155    /*
156     * create @Watch callback, e.g. (propertyName: string): void => {this.<callbackName>(propertyName)}.
157     */
158    static createWatchCallback(callbackName: string): arkts.ArrowFunctionExpression {
159        return factory.createArrowFunctionWithParamsAndBody(
160            undefined,
161            [
162                arkts.factory.createParameterDeclaration(
163                    arkts.factory.createIdentifier('_', UIFactory.createTypeReferenceFromString('string')),
164                    undefined
165                ),
166            ],
167            arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
168            false,
169            [
170                arkts.factory.createExpressionStatement(
171                    arkts.factory.createCallExpression(factory.generateThisCall(callbackName), undefined, [
172                        arkts.factory.createIdentifier('_'),
173                    ])
174                ),
175            ]
176        );
177    }
178
179    /*
180     * create this.<name> with optional or nonNullable.
181     */
182    static generateThisCall(name: string, optional: boolean = false, nonNull: boolean = false): arkts.Expression {
183        const member: arkts.Expression = arkts.factory.createMemberExpression(
184            arkts.factory.createThisExpression(),
185            arkts.factory.createIdentifier(`${name}`),
186            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
187            false,
188            optional
189        );
190        return nonNull ? arkts.factory.createTSNonNullExpression(member) : member;
191    }
192
193    /*
194     * create `initializers!.<newName>!.<getOrSet>(<args>)`.
195     */
196    static createBackingGetOrSetCall(
197        newName: string,
198        getOrSet: string,
199        args: arkts.AstNode[] | undefined
200    ): arkts.CallExpression {
201        return arkts.factory.createCallExpression(
202            arkts.factory.createMemberExpression(
203                arkts.factory.createTSNonNullExpression(
204                    factory.createNonNullOrOptionalMemberExpression('initializers', newName, false, true)
205                ),
206                arkts.factory.createIdentifier(getOrSet),
207                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
208                false,
209                false
210            ),
211            undefined,
212            args
213        );
214    }
215
216    /*
217     * create `new <className><typeAnnotation>(<args>)`.
218     */
219    static createNewDecoratedInstantiate(
220        className: string,
221        typeAnnotation: arkts.TypeNode | undefined,
222        args: arkts.Expression[] | undefined
223    ): arkts.ETSNewClassInstanceExpression {
224        return arkts.factory.createETSNewClassInstanceExpression(
225            arkts.factory.createTypeReference(
226                arkts.factory.createTypeReferencePart(
227                    arkts.factory.createIdentifier(className),
228                    arkts.factory.createTSTypeParameterInstantiation(typeAnnotation ? [typeAnnotation.clone()] : [])
229                )
230            ),
231            args?.length ? args : []
232        );
233    }
234
235    /*
236     * create `this.addProvidedVar<number>(<originName>, <alias>, initializers?.<originalName> ?? <property.value>, <allowOverride>, watchFunc)`.
237     */
238    static generateAddProvideVarCall(
239        originalName: string,
240        property: arkts.ClassProperty,
241        alias: string,
242        allowOverride: boolean = false
243    ): arkts.CallExpression {
244        const args: arkts.Expression[] = [
245            arkts.factory.create1StringLiteral(originalName),
246            arkts.factory.create1StringLiteral(alias),
247            arkts.factory.createBinaryExpression(
248                factory.createBlockStatementForOptionalExpression(
249                    arkts.factory.createIdentifier('initializers'),
250                    originalName
251                ),
252                property.value ?? arkts.factory.createUndefinedLiteral(),
253                arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING
254            ),
255            arkts.factory.createBooleanLiteral(allowOverride),
256        ];
257        judgeIfAddWatchFunc(args, property);
258        return arkts.factory.createCallExpression(
259            arkts.factory.createMemberExpression(
260                arkts.factory.createThisExpression(),
261                arkts.factory.createIdentifier('addProvidedVar'),
262                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
263                false,
264                false
265            ),
266            property.typeAnnotation ? [property.typeAnnotation.clone()] : undefined,
267            args
268        );
269    }
270
271    /*
272     * create `this.initConsume<number>(<originalName>, <alias>, watchFunc)`.
273     */
274    static generateInitConsumeCall(
275        originalName: string,
276        property: arkts.ClassProperty,
277        alias: string
278    ): arkts.CallExpression {
279        const args: arkts.Expression[] = [
280            arkts.factory.create1StringLiteral(originalName),
281            arkts.factory.create1StringLiteral(alias),
282        ];
283        judgeIfAddWatchFunc(args, property);
284        return arkts.factory.createCallExpression(
285            arkts.factory.createMemberExpression(
286                arkts.factory.createThisExpression(),
287                arkts.factory.createIdentifier('initConsume'),
288                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
289                false,
290                false
291            ),
292            property.typeAnnotation ? [property.typeAnnotation.clone()] : undefined,
293            args
294        );
295    }
296}
297