* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as arkts from '@koalaui/libarkts';
import { expectName } from '../../common/arkts-utils';
import { GetSetTypes, StateManagementTypes } from '../../common/predefines';
import { checkIsStructMethodFromInfo } from '../../collectors/ui-collectors/utils';
import { ClassInfo, computedField } from '../utils';
import { generateThisBacking, generateGetOrSetCall } from './utils';
import {
BaseMethodTranslator,
MethodCacheTranslator,
MethodCacheTranslatorOptions,
MethodTranslator,
MethodTranslatorOptions,
} from './base';
import { factory as UIFactory } from '../ui-factory';
import { factory } from './factory';
import { ComputedCache } from './cache/computedCache';
import { PropertyCache } from './cache/propertyCache';
function fieldWithComputedMethod(
this: BaseMethodTranslator,
newName: string,
originalName: string,
modifiers: arkts.Es2pandaModifierFlags
): arkts.ClassProperty {
const field: arkts.ClassProperty = arkts.factory.createClassProperty(
arkts.factory.createIdentifier(newName),
factory.generateStateMgmtFactoryCall(
StateManagementTypes.MAKE_COMPUTED,
this.returnType,
[
arkts.factory.createArrowFunctionExpression(
UIFactory.createScriptFunction({
body: this.method.function.body?.clone(),
modifiers: modifiers,
flags:
arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW |
arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN,
})
),
arkts.factory.createStringLiteral(originalName),
],
false
),
undefined,
modifiers,
false
);
return field;
}
function getterWithComputedMethod(
this: BaseMethodTranslator,
newName: string,
className: string,
isStatic: boolean
): arkts.MethodDefinition {
const scriptFunction = this.method.function;
scriptFunction.addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN);
scriptFunction.setBody(
arkts.factory.createBlockStatement([arkts.factory.createReturnStatement(computedGetCall(newName, className, isStatic))])
);
return this.method;
}
function resetOnReuseWithComputedMethod(
this: BaseMethodTranslator,
newName: string
): arkts.ExpressionStatement {
return factory.createResetOnReuseStmt(newName);
}
function computedGetCall(newName: string, className: string, isStatic: boolean): arkts.CallExpression {
const thisValue: arkts.Expression = isStatic
? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(className), newName)
: generateThisBacking(newName, false, true);
return generateGetOrSetCall(thisValue, GetSetTypes.GET);
}
export interface IComputedTranslator {
field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty;
getter(newName: string, isStatic: boolean): arkts.MethodDefinition;
resetOnReuse(newName: string): arkts.ExpressionStatement;
}
* @deprecated
*/
export class ComputedTranslator extends MethodTranslator implements IComputedTranslator {
private isStatic: boolean;
constructor(options: MethodTranslatorOptions) {
super(options);
this.isStatic = this.method.isStatic;
}
field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty {
const modifiers = isStatic ? this.method.modifierFlags : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE;
return fieldWithComputedMethod.bind(this)(newName, originalName, modifiers);
}
getter(newName: string, isStatic: boolean): arkts.MethodDefinition {
return getterWithComputedMethod.bind(this)(newName, this.classInfo.className, isStatic);
}
resetOnReuse(newName: string): arkts.ExpressionStatement {
return resetOnReuseWithComputedMethod.bind(this)(newName);
}
translateMember(): arkts.AstNode[] {
if (this.isDecl) {
return [this.method];
}
const originalName: string = expectName(this.method.id);
const newName: string = computedField(originalName);
if (this.classInfo.isFromStruct && !this.isStatic) {
this.cacheTranslatedInitializer(newName);
}
return this.translateWithoutInitializer(newName, originalName);
}
cacheTranslatedInitializer(newName: string): void {
ComputedCache.getInstance().collectComputed(this.classInfo.className, { newName });
const resetStateVars: arkts.Statement = this.resetOnReuse(newName);
PropertyCache.getInstance().collectResetStateVars(this.classInfo.className, [resetStateVars]);
}
translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] {
const field = this.field(newName, originalName, this.isStatic);
const getter = this.getter(newName, this.isStatic);
return [field, getter];
}
}
export class ComputedCacheTranslator extends MethodCacheTranslator implements IComputedTranslator {
private isStatic: boolean;
constructor(options: MethodCacheTranslatorOptions) {
super(options);
this.isStatic = this.method.isStatic;
}
field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty {
const modifiers = isStatic ? this.methodInfo.modifiers! : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE;
return fieldWithComputedMethod.bind(this)(newName, originalName, modifiers);
}
getter(newName: string, isStatic: boolean): arkts.MethodDefinition {
let className: string;
if (checkIsStructMethodFromInfo(this.methodInfo)) {
className = this.methodInfo.structInfo?.name!;
} else {
className = this.methodInfo.classInfo?.name!;
}
return getterWithComputedMethod.bind(this)(newName, className, isStatic);
}
resetOnReuse(newName: string): arkts.ExpressionStatement {
return resetOnReuseWithComputedMethod.bind(this)(newName);
}
translateMember(): arkts.AstNode[] {
if (this.isDecl) {
return [this.method];
}
const originalName: string = this.methodInfo.name!;
const newName: string = computedField(originalName);
this.cacheTranslatedInitializer(newName);
return this.translateWithoutInitializer(newName, originalName);
}
cacheTranslatedInitializer(newName: string): void {
if (!checkIsStructMethodFromInfo(this.methodInfo) || this.isStatic || !this.methodInfo.structInfo?.name) {
return;
}
const structName: string = this.methodInfo.structInfo.name;
ComputedCache.getInstance().collectComputed(structName, { newName });
const resetStateVars: arkts.Statement = this.resetOnReuse(newName);
PropertyCache.getInstance().collectResetStateVars(structName, [resetStateVars]);
}
translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] {
const field = this.field(newName, originalName, this.isStatic);
const getter = this.getter(newName, this.isStatic);
return [field, getter];
}
}