* Copyright (c) 2026 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';
export enum LifecycleMethodType {
ABOUT_TO_APPEAR = 'aboutToAppear',
ON_DID_BUILD = 'onDidBuild',
ABOUT_TO_DISAPPEAR = 'aboutToDisappear',
ABOUT_TO_REUSE = 'aboutToReuse',
ABOUT_TO_RECYCLE = 'aboutToRecycle'
}
export interface LifecycleMethodInfo {
methodName: string;
methodType: LifecycleMethodType;
hasReuseParam: boolean;
reuseParams?: arkts.ETSParameterExpression[];
}
export interface LifecycleObserverCallInfo {
internalVarDeclarations: arkts.Statement[];
callbackBodyMap: Map<LifecycleMethodType, arkts.Statement[]>;
varMap: Map<string, string>;
}
export type LifecycleObserverCallGenerator = (callInfo: LifecycleObserverCallInfo) => arkts.Statement[];
export class ComponentLifecycleCache {
private _initCache: Map<string, string[]>;
private _lifecycleObserverCache: Map<string, LifecycleObserverCallInfo>;
private static instance: ComponentLifecycleCache | null = null;
private constructor() {
this._initCache = new Map<string, string[]>();
this._lifecycleObserverCache = new Map<string, LifecycleObserverCallInfo>();
}
static getInstance(): ComponentLifecycleCache {
if (!this.instance) {
this.instance = new ComponentLifecycleCache();
}
return this.instance;
}
reset(): void {
this._initCache.clear();
this._lifecycleObserverCache.clear();
}
* Get all @ComponentInit method names for a class
*/
getCachedInitMethods(className: string): string[] {
return this._initCache.get(className) ?? [];
}
* Get cached @ComponentInit method call statements for a class
*/
getCachedInitMethodCalls(className: string): arkts.ExpressionStatement[] {
return this.getCachedInitMethods(className).map((methodName: string) => {
return arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(
arkts.factory.createMemberExpression(
arkts.factory.createThisExpression(),
arkts.factory.createIdentifier(methodName),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
),
[],
undefined,
false,
false
)
);
});
}
* Collect a @ComponentInit method for a class
*/
collectInitMethod(className: string, methodName: string): void {
let methods: string[] = [];
if (this._initCache.has(className)) {
methods = this._initCache.get(className)!;
}
if (!methods.includes(methodName)) {
methods.push(methodName);
this._initCache.set(className, methods);
}
}
* Get cached lifecycle observer registration statements for a class
*/
getCachedLifecycleObserverCalls(className: string, generator: LifecycleObserverCallGenerator): arkts.Statement[] {
const callInfo = this._lifecycleObserverCache.get(className);
if (!callInfo || callInfo.internalVarDeclarations.length === 0) {
return [];
}
return generator(callInfo);
}
* Collect a lifecycle method for a class
*/
collectLifecycleMethod(className: string, methodInfo: LifecycleMethodInfo): void {
const callInfo = this.getOrCreateLifecycleObserverCallInfo(className);
const internalVarName = this.collectInternalMethodReference(callInfo, methodInfo.methodName);
this.collectLifecycleCallbackStatement(callInfo, methodInfo, internalVarName);
}
private getOrCreateLifecycleObserverCallInfo(className: string): LifecycleObserverCallInfo {
if (this._lifecycleObserverCache.has(className)) {
return this._lifecycleObserverCache.get(className)!;
}
const callInfo: LifecycleObserverCallInfo = {
internalVarDeclarations: [],
callbackBodyMap: new Map<LifecycleMethodType, arkts.Statement[]>(),
varMap: new Map<string, string>(),
};
this._lifecycleObserverCache.set(className, callInfo);
return callInfo;
}
private collectInternalMethodReference(callInfo: LifecycleObserverCallInfo, methodName: string): string {
const cachedInternalVarName = callInfo.varMap.get(methodName);
if (cachedInternalVarName) {
return cachedInternalVarName;
}
const internalVarName = `__${methodName}__Internal`;
callInfo.varMap.set(methodName, internalVarName);
callInfo.internalVarDeclarations.push(
ComponentLifecycleCache.createInternalVarDeclaration(internalVarName, methodName)
);
return internalVarName;
}
private collectLifecycleCallbackStatement(
callInfo: LifecycleObserverCallInfo,
methodInfo: LifecycleMethodInfo,
internalVarName: string
): void {
let callbackBody = callInfo.callbackBodyMap.get(methodInfo.methodType);
if (!callbackBody) {
callbackBody = [];
callInfo.callbackBodyMap.set(methodInfo.methodType, callbackBody);
}
callbackBody.push(
ComponentLifecycleCache.createUnsafeCallStatement(
internalVarName,
methodInfo.methodType === LifecycleMethodType.ABOUT_TO_REUSE && methodInfo.hasReuseParam
)
);
}
private static createInternalVarDeclaration(internalVarName: string, methodName: string): arkts.VariableDeclaration {
return arkts.factory.createVariableDeclaration(
arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST,
[
arkts.factory.createVariableDeclarator(
arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_CONST,
arkts.factory.createIdentifier(internalVarName),
arkts.factory.createMemberExpression(
arkts.factory.createThisExpression(),
arkts.factory.createIdentifier(methodName),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
)
),
]
);
}
private static createUnsafeCallStatement(internalVarName: string, passParams: boolean): arkts.Statement {
const args: arkts.Expression[] = passParams ? [arkts.factory.createIdentifier('params')] : [];
return arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(
arkts.factory.createMemberExpression(
arkts.factory.createIdentifier(internalVarName),
arkts.factory.createIdentifier('unsafeCall'),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
),
args,
undefined,
false,
false
)
);
}
}