* 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 { GenSymGenerator } from '../../common/gensym-generator';
import {
DecoratorNames,
DECORATOR_TYPE_MAP,
StateManagementTypes,
ObservedNames,
MonitorNames,
TypeNames,
NodeCacheNames,
CustomComponentNames,
} from '../../common/predefines';
import { factory as UIFactory } from '../ui-factory';
import {
canCastTypeFromValue,
collectStateManagementTypeImport,
generateThisBacking,
getValueInAnnotation,
hasDecorator,
InitializeValueOptions,
OptionalMemberInfo,
PropertyOptionalFieldOptions,
removeDecorator,
findCachedMemoMetadata,
} from './utils';
import { optionsHasField } from '../utils';
import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../../collectors/memo-collectors/utils';
import { annotation, isNumeric } from '../../common/arkts-utils';
import { PropertyFactoryCallTypeCache, PropertyValueCache } from '../memo-collect-cache';
import { MetaDataCollector } from '../../common/metadata-collector';
import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache';
import { CustomComponentInnerClassPropertyInfo } from 'collectors/ui-collectors/records';
import { PropertyPathNode, PropertyPathResult, resolvePropertyPath } from '../../common/path-resolvers';
const MONITOR_WILDCARD_SUFFIX = '.*';
const MONITOR_WILDCARD_MIN_VERSION = 26;
const MONITOR_WILDCARD_PROPERTY_NAME = 'enableWildcard';
export class factory {
static createStateManagementFactoryGenericType(
propertyValue: arkts.Expression | undefined,
propertyType: arkts.TypeNode | undefined,
initializeValueOptions?: InitializeValueOptions
): arkts.TypeNode | undefined {
if (!propertyType) {
return undefined;
}
if (!!initializeValueOptions?.canDefinitelyBeNonNull) {
if (arkts.isETSUnionType(propertyType)) {
propertyType.setTypes([...propertyType.types, arkts.factory.createETSUndefinedType()]);
return propertyType;
}
return arkts.factory.createETSUnionType([propertyType, arkts.factory.createETSUndefinedType()]);
}
return propertyType;
}
* generate an substitution for optional expression ?., e.g. `{let _tmp = xxx; _tmp == null ? undefined : xxx}`.
*
* @param object item before ?..
* @param key item after ?..
* @param info optional member information
*/
static createBlockStatementForOptionalExpression(
object: arkts.Expression,
key: string,
info?: OptionalMemberInfo,
alternateFn?: (id: string, key: string) => arkts.Expression
): arkts.Expression {
let id = GenSymGenerator.getInstance().id(key);
const alternate = !!alternateFn ? alternateFn(id, key) : this.generateConditionalAlternate(id, key, info);
const statements: arkts.Statement[] = [
UIFactory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object),
UIFactory.generateTernaryExpression(id, alternate),
];
return arkts.factory.createBlockExpression(statements);
}
* generate an substitution for optional __options_has expression ?., e.g. `{let <id> = <object>; <id> == null ? undefined : <id>.__options_has_<key>}`.
*
* @param object item before ?..
* @param key item after ?..
* @param info optional member information
*/
static createBlockStatementForOptionsHasMemberExpression(
object: arkts.Expression,
id: string,
key: string
): arkts.Expression {
const alternate = UIFactory.generateMemberExpression(arkts.factory.createIdentifier(id), optionsHasField(key));
const statements: arkts.Statement[] = [
UIFactory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object),
UIFactory.generateTernaryExpression(id, alternate),
];
return arkts.factory.createBlockExpression(statements);
}
static generateConditionalAlternate(testLeft: string, key: string, info?: OptionalMemberInfo): arkts.Expression {
const leftIdent: arkts.Identifier = arkts.factory.createIdentifier(testLeft);
const alternate: arkts.MemberExpression = UIFactory.generateMemberExpression(
info?.isNonNull ? arkts.factory.createTSNonNullExpression(leftIdent) : leftIdent,
info?.isNumeric ? '$_get' : key
);
return info?.isCall
? arkts.factory.createCallExpression(alternate, [], undefined, false, false)
: info?.isNumeric
? arkts.factory.createCallExpression(alternate, [
arkts.factory.createNumberLiteral(Number(key)),
], undefined, false, false)
: alternate;
}
* generate an substitution for two optional expression ?., e.g. a?.b?.c.
*
* @param node entry wrapper class declaration node.
*/
static createDoubleBlockStatementForOptionalExpression(
object: arkts.Expression,
key1: string,
key2: string
): arkts.Expression {
let id = GenSymGenerator.getInstance().id(key1);
let initial: arkts.Expression = factory.createBlockStatementForOptionalExpression(object, key1);
const alternate = this.generateConditionalAlternate(id, key2);
const statements: arkts.Statement[] = [
UIFactory.generateLetVariableDecl(arkts.factory.createIdentifier(id), initial),
UIFactory.generateTernaryExpression(id, alternate),
];
return arkts.factory.createBlockExpression(statements);
}
* generate an memberExpression with nonNull or optional, e.g. object.property, object?.property or object!.property
*
* @param object item before point.
* @param property item after point.
*/
static createNonNullOrOptionalMemberExpression(
object: string,
property: string,
optional: boolean,
nonNull: boolean
): arkts.Expression {
const objectNode: arkts.Identifier = arkts.factory.createIdentifier(object);
return arkts.factory.createMemberExpression(
nonNull ? arkts.factory.createTSNonNullExpression(objectNode) : objectNode,
arkts.factory.createIdentifier(property),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
optional
);
}
* create `(<params>)<typeParams>: <returnType> => { <bodyStatementsList> }`.
*/
static createArrowFunctionWithParamsAndBody(
typeParams: arkts.TSTypeParameterDeclaration | undefined,
params: arkts.Expression[] | undefined,
returnType: arkts.TypeNode | undefined,
hasReceiver: boolean,
bodyStatementsList: arkts.Statement[],
hasReturn?: boolean
): arkts.ArrowFunctionExpression {
let flag = arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW;
if (hasReturn) {
flag |= arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN;
}
return arkts.factory.createArrowFunctionExpression(
arkts.factory.createScriptFunction(
arkts.BlockStatement.createBlockStatement(bodyStatementsList),
typeParams, params ? params : [], returnType, hasReceiver,
flag,
arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE,
undefined,
undefined
)
);
}
* create @Watch callback, e.g. (propertyName: string): void => {this.<callbackName>(propertyName)}.
*/
static createWatchCallback(callbackName: string): arkts.ArrowFunctionExpression {
return factory.createArrowFunctionWithParamsAndBody(
undefined,
[
arkts.factory.createETSParameterExpression(
arkts.factory.createIdentifier('_', UIFactory.createTypeReferenceFromString('string')),
false,
undefined
),
],
arkts.factory.createETSPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID),
false,
[
arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(generateThisBacking(callbackName), [
arkts.factory.createIdentifier('_'),
], undefined, false, false)
),
]
);
}
* create `initializers!.<newName>!.<getOrSet>(<args>)`.
*/
static createBackingGetOrSetCall(
newName: string,
getOrSet: string,
args: arkts.Expression[]
): arkts.CallExpression {
return arkts.factory.createCallExpression(
arkts.factory.createMemberExpression(
arkts.factory.createTSNonNullExpression(
factory.createNonNullOrOptionalMemberExpression('initializers', newName, false, true)
),
arkts.factory.createIdentifier(getOrSet),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
),
args,
undefined,
false,
false
);
}
* create `new <className><typeAnnotation>(<args>)`.
*/
static createNewDecoratedInstantiate(
className: string,
typeAnnotation: arkts.TypeNode | undefined,
args: arkts.Expression[] | undefined
): arkts.ETSNewClassInstanceExpression {
return arkts.factory.createETSNewClassInstanceExpression(
arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(className),
arkts.factory.createTSTypeParameterInstantiation(typeAnnotation ? [typeAnnotation.clone()] : [])
)
),
args?.length ? args : []
);
}
* create `StateMgmtFactory.<makeType><typeArguments>(this, ...<args>);`.
*/
static generateStateMgmtFactoryCall(
makeType: StateManagementTypes,
typeArguments: arkts.TypeNode | undefined,
args: arkts.Expression[],
argsContainsThis: boolean,
memoMetadata?: AstNodeCacheValueMetadata
): arkts.CallExpression {
collectStateManagementTypeImport(StateManagementTypes.STATE_MANAGEMENT_FACTORY);
if (!!typeArguments && !!memoMetadata) {
PropertyFactoryCallTypeCache.getInstance().collect({ node: typeArguments, metadata: memoMetadata });
}
return arkts.factory.createCallExpression(
UIFactory.generateMemberExpression(
arkts.factory.createIdentifier(StateManagementTypes.STATE_MANAGEMENT_FACTORY),
makeType
),
[...(argsContainsThis ? [arkts.factory.createThisExpression()] : []), ...args],
typeArguments ? arkts.factory.createTSTypeParameterInstantiation([typeArguments]) : undefined,
false,
false
);
}
* create if statement in __updateStruct method.
*/
static createIfInUpdateStruct(
originalName: string,
member: arkts.Expression,
args: arkts.Expression[]
): arkts.IfStatement {
const initializers = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME);
const binaryItem = factory.createBlockStatementForOptionalExpression(
initializers,
optionsHasField(originalName)
);
return arkts.factory.createIfStatement(
binaryItem,
arkts.factory.createBlockStatement([
arkts.factory.createExpressionStatement(arkts.factory.createCallExpression(member, args, undefined, false, false)),
])
);
}
* create `initializers!.<originalName> as <type>`.
*/
static generateDefiniteInitializers(type: arkts.TypeNode | undefined, originalName: string): arkts.Expression {
return arkts.factory.createTSAsExpression(
factory.createNonNullOrOptionalMemberExpression(
CustomComponentNames.COMPONENT_INITIALIZERS_NAME,
originalName,
false,
true
),
type ?? undefined,
false
);
}
static addWatchFunc(args: arkts.Expression[], property: arkts.ClassProperty): void {
const watchStr: string | undefined = getValueInAnnotation(property, DecoratorNames.WATCH);
if (watchStr) {
args.push(factory.createWatchCallback(watchStr));
}
}
static addWatchFuncProperty(propName: string, property: arkts.ClassProperty): arkts.Property | undefined {
const watchStr: string | undefined = getValueInAnnotation(property, DecoratorNames.WATCH);
if (watchStr) {
return arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(propName),
factory.createWatchCallback(watchStr),
false,
false
);
}
return undefined;
}
static createOptionalClassProperty(
options: PropertyOptionalFieldOptions
): arkts.ClassProperty {
const { name, propertyType, modifiers, stateManagementType, needMemo, isRequired } = options;
const newType: arkts.TypeNode | undefined = !stateManagementType
? (propertyType ?? UIFactory.createTypeReferenceFromString(TypeNames.ANY))
: propertyType;
if (needMemo && !!newType && arkts.isETSFunctionType(newType) && findCanAddMemoFromTypeAnnotation(newType).canAddMemo) {
addMemoAnnotation(newType);
}
let newPropertyType = !!stateManagementType ? factory.createStageManagementType(stateManagementType, propertyType) : newType;
if (!isRequired && !!newPropertyType && arkts.isETSFunctionType(newPropertyType)) {
newPropertyType = arkts.factory.createETSUnionType([newPropertyType, arkts.factory.createETSUndefinedType()]);
}
const newProperty = arkts.factory.createClassProperty(
arkts.factory.createIdentifier(name),
undefined,
newPropertyType,
modifiers,
false
);
if (isRequired) {
newProperty.setIsImmediateInit();
} else {
newProperty.modifierFlags |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL;
}
return newProperty;
}
static createStageManagementType(
stageManagementType: StateManagementTypes,
type: arkts.TypeNode | undefined
): arkts.ETSTypeReference {
collectStateManagementTypeImport(stageManagementType);
return arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(stageManagementType),
arkts.factory.createTSTypeParameterInstantiation([type ?? arkts.factory.createETSUndefinedType()])
)
);
}
* create watch related members in Observed/Track classes
*/
static createWatchMembers(isDecl: boolean): arkts.AstNode[] {
const members: arkts.AstNode[] = [];
if (!isDecl) {
const subscribedWatches: arkts.ClassProperty = arkts.factory.createClassProperty(
arkts.factory.createIdentifier(ObservedNames.SUBSCRIBED_WATCHES),
factory.generateStateMgmtFactoryCall(StateManagementTypes.MAKE_SUBSCRIBED_WATCHES, undefined, [], false),
arkts.factory.createETSUnionType([
arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(StateManagementTypes.SUBSCRIBED_WATCHES)
)
),
arkts.factory.createETSUndefinedType()
]),
arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE,
false
);
subscribedWatches.setAnnotations([
annotation(DecoratorNames.JSONSTRINGIFYIGNORE),
annotation(DecoratorNames.JSONPARSEIGNORE),
]);
collectStateManagementTypeImport(StateManagementTypes.SUBSCRIBED_WATCHES);
members.push(subscribedWatches);
}
const addWatchSubscriber = factory.createWatchMethod(
ObservedNames.ADD_WATCH_SUBSCRIBER,
arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID,
ObservedNames.WATCH_ID,
StateManagementTypes.WATCH_ID_TYPE,
false,
isDecl
);
members.push(addWatchSubscriber);
const removeWatchSubscriber = factory.createWatchMethod(
ObservedNames.REMOVE_WATCH_SUBSCRIBER,
arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_BOOLEAN,
ObservedNames.WATCH_ID,
StateManagementTypes.WATCH_ID_TYPE,
true,
isDecl
);
collectStateManagementTypeImport(StateManagementTypes.WATCH_ID_TYPE);
members.push(removeWatchSubscriber);
const executeOnSubscribingWatches = factory.createWatchMethod(
ObservedNames.EXECUATE_WATCHES,
arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID,
ObservedNames.PROPETY_NAME,
'string',
false,
isDecl
);
members.push(executeOnSubscribingWatches);
return members;
}
* helper for createWatchMembers to create watch methods
*/
static createWatchMethod(
methodName: string,
returnType: arkts.Es2pandaPrimitiveType,
paramName: string,
paramType: string,
isReturnStatement: boolean,
isDecl: boolean
): arkts.MethodDefinition {
let body: arkts.BlockStatement | undefined;
let modifier = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
if (!isDecl) {
const subscribedWatchesAccess = arkts.factory.createMemberExpression(
arkts.factory.createThisExpression(),
arkts.factory.createIdentifier(ObservedNames.SUBSCRIBED_WATCHES),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
);
const undefinedCondition = arkts.factory.createBinaryExpression(
subscribedWatchesAccess,
arkts.factory.createUndefinedLiteral(),
arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL
);
const innerStatement = isReturnStatement
? arkts.factory.createReturnStatement(
arkts.factory.createCallExpression(
factory.thisSubscribedWatchesMember(methodName),
[arkts.factory.createIdentifier(paramName)],
undefined,
false,
false
)
)
: arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(
factory.thisSubscribedWatchesMember(methodName),
[arkts.factory.createIdentifier(paramName)],
undefined,
false,
false
)
);
const ifStatement = arkts.factory.createIfStatement(
undefinedCondition,
arkts.factory.createBlockStatement([innerStatement])
);
const bodyStatements: arkts.Statement[] = [ifStatement];
if (isReturnStatement) {
bodyStatements.push(
arkts.factory.createReturnStatement(
arkts.factory.createBooleanLiteral(false)
)
);
}
body = arkts.factory.createBlockStatement(bodyStatements);
} else {
modifier |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE;
}
return arkts.factory.createMethodDefinition(
arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
arkts.factory.createIdentifier(methodName),
arkts.factory.createFunctionExpression(
arkts.factory.createIdentifier(methodName),
arkts.factory.createScriptFunction(
body,
undefined,
[
arkts.factory.createETSParameterExpression(
arkts.factory.createIdentifier(
paramName,
arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier(paramType))
)
),
false,
undefined
)
],
arkts.factory.createETSPrimitiveType(returnType),
false,
arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
modifier,
arkts.factory.createIdentifier(methodName),
undefined
)
),
modifier,
false
);
}
* helper for createWatchMethod, generates this.subscribedWatches.xxx
*/
static thisSubscribedWatchesMember(member: string): arkts.MemberExpression {
return arkts.factory.createMemberExpression(
arkts.factory.createTSNonNullExpression(
arkts.factory.createMemberExpression(
arkts.factory.createThisExpression(),
arkts.factory.createIdentifier(ObservedNames.SUBSCRIBED_WATCHES),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
)
),
arkts.factory.createIdentifier(member),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
);
}
* create ____V1RenderId related members in Observed/Track classes
*/
static createV1RenderIdMembers(isObservedV2: boolean, isDecl: boolean): arkts.AstNode[] {
const members: arkts.AstNode[] = [];
const setV1RenderId: arkts.MethodDefinition = factory.setV1RenderId(isObservedV2, isDecl);
collectStateManagementTypeImport(StateManagementTypes.RENDER_ID_TYPE);
members.push(setV1RenderId);
return members;
}
* helper for createV1RenderIdMembers to generate setV1RenderId method
*/
static setV1RenderId(isObservedV2: boolean, isDecl: boolean): arkts.MethodDefinition {
let body: arkts.BlockStatement | undefined;
let modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC;
if (!isDecl) {
const bodyStatements: arkts.Statement[] = [];
body = arkts.factory.createBlockStatement(bodyStatements);
} else {
modifiers |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE;
}
return UIFactory.createMethodDefinition({
key: arkts.factory.createIdentifier(ObservedNames.SET_V1_RERENDER_ID),
kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
function: {
body,
params: [
arkts.factory.createETSParameterExpression(
arkts.factory.createIdentifier(
ObservedNames.RERENDER_ID,
UIFactory.createTypeReferenceFromString(StateManagementTypes.RENDER_ID_TYPE)
),
false,
undefined
),
],
returnTypeAnnotation: arkts.factory.createETSPrimitiveType(
arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID
),
flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
modifiers,
},
modifiers,
});
}
* create conditionalAddRef method in Observed/Track classes
*/
static conditionalAddRef(isObservedV2: boolean): arkts.MethodDefinition {
const metaAddRef: arkts.ExpressionStatement = arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(
UIFactory.generateMemberExpression(
arkts.factory.createIdentifier(ObservedNames.META),
ObservedNames.ADD_REF
),
[],
undefined,
false,
false
)
);
collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META);
return UIFactory.createMethodDefinition({
key: arkts.factory.createIdentifier(ObservedNames.CONDITIONAL_ADD_REF),
kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD,
function: {
body: arkts.factory.createBlockStatement([metaAddRef]),
params: [
arkts.factory.createETSParameterExpression(
arkts.factory.createIdentifier(
ObservedNames.META,
UIFactory.createTypeReferenceFromString(StateManagementTypes.MUTABLE_STATE_META)
),
false,
undefined
),
],
returnTypeAnnotation: arkts.factory.createETSPrimitiveType(
arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID
),
flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD,
modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED,
},
modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED,
});
}
* helper for conditionalAddRef to generate shouldAddRef method
*/
static shouldAddRef(metaAddRef: arkts.ExpressionStatement): arkts.IfStatement {
const test: arkts.CallExpression = arkts.factory.createCallExpression(
UIFactory.generateMemberExpression(
arkts.factory.createIdentifier(StateManagementTypes.OBSERVE),
ObservedNames.SHOULD_ADD_REF
),
[generateThisBacking(ObservedNames.V1_RERENDER_ID)],
undefined,
false,
false
);
collectStateManagementTypeImport(StateManagementTypes.OBSERVE);
const consequent: arkts.BlockStatement = arkts.factory.createBlockStatement([metaAddRef]);
return arkts.factory.createIfStatement(test, consequent);
}
* helper to create meta field in classes with only @Observe and no @Track
*/
static createMetaInObservedClass(): arkts.ClassProperty {
collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META);
const meta = arkts.factory.createClassProperty(
arkts.factory.createIdentifier(StateManagementTypes.META),
factory.generateStateMgmtFactoryCall(
StateManagementTypes.MAKE_MUTABLESTATE_META,
undefined,
[arkts.factory.createStringLiteral(`${StateManagementTypes.META}_`)],
true
),
UIFactory.createTypeReferenceFromString(StateManagementTypes.MUTABLE_STATE_META),
arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE,
false
);
meta.setAnnotations([
annotation(DecoratorNames.JSONSTRINGIFYIGNORE),
annotation(DecoratorNames.JSONPARSEIGNORE),
]);
return meta;
}
* add `@memo` to the `@Builder` methods in class.
*/
static addMemoToBuilderClassMethod(method: arkts.MethodDefinition): arkts.MethodDefinition {
if (hasDecorator(method, DecoratorNames.BUILDER)) {
removeDecorator(method, DecoratorNames.BUILDER);
addMemoAnnotation(method.function!);
}
return method;
}
* wrap interface non-undefined property type `T` to `<wrapTypeName><T>`.
*/
static wrapInnerClassPropertyTypeInMethod(type: arkts.TypeNode, wrapTypeName: StateManagementTypes): arkts.TypeNode {
if (arkts.isETSUnionType(type)) {
return arkts.factory.createETSUnionType([
arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(wrapTypeName),
arkts.factory.createTSTypeParameterInstantiation([type.types[0]])
)
),
...type.types.slice(1),
]);
}
return arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(wrapTypeName),
arkts.factory.createTSTypeParameterInstantiation([type])
)
);
}
static wrapInnerClassPropertyTypeInProperty(type: arkts.TypeNode, wrapTypeName: StateManagementTypes): arkts.TypeNode {
return arkts.factory.createETSTypeReference(
arkts.factory.createETSTypeReferencePart(
arkts.factory.createIdentifier(wrapTypeName),
arkts.factory.createTSTypeParameterInstantiation([type])
)
);
}
* wrap interface property parameter that has non-undefined type `T` to `<wrapTypeName><T>`.
*/
static wrapInnerClassPropertyParamExpr(
param: arkts.Expression,
wrapTypeName: StateManagementTypes
): arkts.Expression {
if (!arkts.isETSParameterExpression(param)) {
return param;
}
if (!param.typeAnnotation || !arkts.isETSUnionType(param.typeAnnotation)) {
return param;
}
return arkts.factory.createETSParameterExpression(
arkts.factory.createIdentifier(
param.ident!.name,
factory.wrapInnerClassPropertyTypeInMethod(param.typeAnnotation!, wrapTypeName)
),
param.isOptional,
param.initializer,
param.annotations
);
}
static wrapStateManagementTypeToType(
type: arkts.TypeNode | undefined,
decoratorName: DecoratorNames,
wrapFn: (type: arkts.TypeNode, wrapTypeName: StateManagementTypes) => arkts.TypeNode
): arkts.TypeNode | undefined {
let newType: arkts.TypeNode | undefined;
let wrapTypeName: StateManagementTypes | undefined;
if (!!type && !!(wrapTypeName = DECORATOR_TYPE_MAP.get(decoratorName))) {
newType = wrapFn(type, wrapTypeName);
collectStateManagementTypeImport(wrapTypeName);
}
return newType;
}
static wrapStateManagementTypeToParam(
param: arkts.Expression | undefined,
decoratorName: DecoratorNames,
metadata?: AstNodeCacheValueMetadata,
): arkts.Expression | undefined {
let newParam: arkts.Expression | undefined;
let wrapTypeName: StateManagementTypes | undefined;
if (!!param && !!(wrapTypeName = DECORATOR_TYPE_MAP.get(decoratorName))) {
newParam = factory.wrapInnerClassPropertyParamExpr(param, wrapTypeName);
const currentMetadata = findCachedMemoMetadata(param);
if (!!metadata) {
NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newParam, currentMetadata || metadata);
}
collectStateManagementTypeImport(wrapTypeName);
}
return newParam;
}
* Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`)
* to `<wrapTypeName><T> | undefined`, where `<wrapTypeName>` is getting from `DecoratorName`;
*
* @param method expecting getter with decorator annotation and a setter with decorator annotation in the overloads.
*/
static wrapStateManagementTypeToMethodInInnerClass(
method: arkts.MethodDefinition,
decorator: DecoratorNames,
metadata?: AstNodeCacheValueMetadata,
): arkts.MethodDefinition {
if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) {
const func = method.function!;
const newType: arkts.TypeNode | undefined = factory.wrapStateManagementTypeToType(
func.returnTypeAnnotation,
decorator,
factory.wrapInnerClassPropertyTypeInMethod
);
removeDecorator(method, decorator);
if (!!newType) {
const currentMetadata = findCachedMemoMetadata(func.returnTypeAnnotation!)
if (!!metadata || !!currentMetadata) {
NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newType, currentMetadata || metadata);
}
func.setReturnTypeAnnotation(newType);
}
return method;
}
if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) {
const func = method.function!;
const newParam: arkts.Expression | undefined = factory.wrapStateManagementTypeToParam(
method.function.params.at(0),
decorator,
metadata
);
removeDecorator(method, decorator);
if (!!newParam) {
func.setParams([newParam]);
}
return method;
}
return method;
}
* create external assignment node, e.g. `initializers?.<originalName> ?? <property>.value` or `initializers!.<originalName>!`.
*
* @param property class property node.
* @param propertyType class property type.
* @param originalName property name.
*/
static generateInitializeValue(
propertyValue: arkts.Expression | undefined,
propertyType: arkts.TypeNode | undefined,
originalName: string,
options?: InitializeValueOptions,
isMemoCached?: boolean,
metadata?: arkts.AstNodeCacheValueMetadata
): arkts.Expression {
if (options?.shouldCheckNonNull) {
const id: string = GenSymGenerator.getInstance().id(originalName);
const optionsType: arkts.TypeNode | undefined = propertyType?.clone();
const optionsValue: arkts.Expression = factory.generateDefiniteInitializers(optionsType, originalName);
const canCastType: boolean = canCastTypeFromValue(propertyValue);
const defaultType: arkts.TypeNode | undefined = canCastType && !!propertyType ? propertyType.clone() : undefined;
const defaultRawValue: arkts.Expression = !!propertyValue ? propertyValue : arkts.factory.createUndefinedLiteral();
const defaultValue: arkts.Expression = !!defaultType
? arkts.factory.createTSAsExpression(defaultRawValue, defaultType, false)
: defaultRawValue;
if (isMemoCached) {
if (!!optionsType) {
PropertyValueCache.getInstance().collect({ value: optionsType, shouldCache: isMemoCached, metadata});
}
if (!!defaultType) {
PropertyValueCache.getInstance().collect({ value: defaultType, shouldCache: isMemoCached, metadata });
}
}
return arkts.factory.createConditionalExpression(
factory.createBlockStatementForOptionsHasMemberExpression(
arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME),
id,
originalName
),
optionsValue,
defaultValue
);
}
if (!!options?.isRequired || !propertyValue) {
return factory.generateDefiniteInitializers(propertyType, originalName);
}
const outInitialize: arkts.Expression = factory.createBlockStatementForOptionalExpression(
arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME),
originalName,
{ isNonNull: options?.isRequired }
);
const binaryItem: arkts.Expression = arkts.factory.createBinaryExpression(
outInitialize,
propertyValue,
arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING
);
const canCastType: boolean = canCastTypeFromValue(propertyValue);
const finalBinary: arkts.Expression = !canCastType || !propertyType
? binaryItem
: arkts.factory.createTSAsExpression(binaryItem, propertyType, false);
return finalBinary;
}
* Wrap to the type of the property (expecting an union type with `T` and `undefined`)
* to `<wrapTypeName><T> | undefined`, where `<wrapTypeName>` is getting from `DecoratorName`;
*
* @param property expecting property with decorator annotation.
*/
static wrapStateManagementTypeToPropertyInInnerClass(
property: arkts.ClassProperty,
decorator: DecoratorNames
): arkts.ClassProperty {
const newType: arkts.TypeNode | undefined = factory.wrapStateManagementTypeToType(
property.typeAnnotation,
decorator,
factory.wrapInnerClassPropertyTypeInProperty
);
removeDecorator(property, decorator);
if (!!newType) {
property.setTypeAnnotation(newType);
}
return property;
}
static generateinitAssignment(
monitorItem: string[] | undefined,
originalName: string,
newName: string,
isFromStruct: boolean,
paramsLength: number,
definition?: arkts.ClassDefinition
): arkts.ExpressionStatement {
if (paramsLength === 0) {
collectStateManagementTypeImport(StateManagementTypes.I_MONITOR);
}
const thisValue: arkts.Expression = generateThisBacking(newName, false, false);
collectStateManagementTypeImport(StateManagementTypes.IMONITOR_PATH_INFO);
const args: arkts.Expression[] = [
this.generatePathArg(definition, monitorItem),
this.generateLambdaArg(originalName, paramsLength)];
const compatibleVersion = MetaDataCollector.getInstance().projectConfig?.compatibleSdkVersion;
if (compatibleVersion !== undefined && compatibleVersion >= 24) {
const makeMonitorOptions = arkts.factory.createObjectExpression(
[
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.OWNER),
isFromStruct ? arkts.factory.createThisExpression() : arkts.factory.createUndefinedLiteral(),
false, false
),
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.FUNCTION_NAME),
arkts.factory.createStringLiteral(originalName),
false, false
),
]
);
collectStateManagementTypeImport(StateManagementTypes.MAKE_MONITOR_OPTIONS);
args.push(arkts.factory.createTSAsExpression(
makeMonitorOptions,
UIFactory.createTypeReferenceFromString(StateManagementTypes.MAKE_MONITOR_OPTIONS),
false
));
} else if (isFromStruct) {
args.push(arkts.factory.createThisExpression());
}
const right: arkts.CallExpression = factory.generateStateMgmtFactoryCall(
StateManagementTypes.MAKE_MONITOR,
undefined,
args,
false
);
return arkts.factory.createExpressionStatement(
arkts.factory.createAssignmentExpression(
thisValue,
right,
arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION
)
);
}
static generatePathArg(definition?: arkts.ClassDefinition, monitorItem?: string[]): arkts.ArrayExpression {
if (!monitorItem || monitorItem.length <= 0) {
return arkts.factory.createArrayExpression([]);
}
const params = monitorItem.map((itemName: string) => {
return arkts.factory.createTSAsExpression(
factory.createMonitorPathsInfoParameter(itemName, definition),
UIFactory.createTypeReferenceFromString(StateManagementTypes.IMONITOR_PATH_INFO),
false
);
});
return arkts.factory.createArrayExpression(params);
}
static generateLambdaArg(originalName: string, paramsLength: number): arkts.ArrowFunctionExpression {
return arkts.factory.createArrowFunctionExpression(
UIFactory.createScriptFunction({
params: [UIFactory.createParameterDeclaration(MonitorNames.M_PARAM, MonitorNames.I_MONITOR)],
body: arkts.factory.createBlockStatement([
arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(generateThisBacking(originalName),
paramsLength > 0 ? [arkts.factory.createIdentifier(MonitorNames.M_PARAM)] : [],
undefined, false, false)
),
]),
flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
})
);
}
static generateMonitorVariable(itemNameSplit: string[]): arkts.Expression {
const objectFirst: arkts.Expression = generateThisBacking(itemNameSplit[0]);
if (itemNameSplit.length === 1) {
return objectFirst;
}
itemNameSplit.shift();
return this.recursiveCreateOptionalMember(objectFirst, itemNameSplit);
}
* recursively create member expression with <object> node and property name in <resNameArr>.
*
* @param typeAnnotation expecting property's original type annotation.
*/
static recursiveCreateOptionalMember(object: arkts.Expression, resNameArr: string[]): arkts.Expression {
if (resNameArr.length <= 0) {
return object;
}
const optionalInfo: OptionalMemberInfo = { isNumeric: false };
if (isNumeric(resNameArr[0])) {
optionalInfo.isNumeric = true;
}
const newMember: arkts.Expression = this.createBlockStatementForOptionalExpression(
object,
resNameArr[0],
optionalInfo
);
resNameArr.shift();
return this.recursiveCreateOptionalMember(newMember, resNameArr);
}
* Check if property path contains union types (nodes with multiple branches).
* Returns the PropertyPathResult if union types are found, undefined otherwise.
*
* @param definition Class definition for property resolution.
* @param monitorItem Property path to check.
* @param hasWildcard Whether wildcard support is enabled.
*/
private static findUnionTypesInPropertyPath(
definition: arkts.ClassDefinition,
monitorItem: string,
hasWildcard: boolean
): PropertyPathResult | undefined {
const propertyPathResult = resolvePropertyPath(definition, monitorItem, { enableWildcard: hasWildcard });
let current: PropertyPathNode | null = propertyPathResult.root;
while (current) {
if (current.branchCount > 1) {
return propertyPathResult;
}
current = current.branchCount === 1 ? current.branches[0].next : null;
}
return undefined;
}
* Generate blocks for handling union types in property paths.
* Creates instanceof checks and nested if-else statements to navigate union type branches.
*
* @param propertyPathResult Resolved property path containing union type information.
* @param itemNameSplit Split property path segments.
* @returns Array of statements for union type path handling.
*/
private static generateUnionTypePathBlocks(
propertyPathResult: PropertyPathResult,
itemNameSplit: string[]
): arkts.Statement[] {
const blocks: arkts.Statement[] = [];
blocks.push(
UIFactory.generateLetVariableDecl(
arkts.factory.createIdentifier('x', UIFactory.createTypeReferenceFromString('Any')),
arkts.factory.createMemberExpression(
arkts.factory.createThisExpression(),
arkts.factory.createIdentifier(itemNameSplit[0]),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, false, false
)
)
);
const resultPaths = propertyPathResult.getAllResultPaths();
for (let varIdx = 1; varIdx < resultPaths[0].length; varIdx++) {
let elseBranch: arkts.Statement = arkts.factory.createReturnStatement(
arkts.factory.createUndefinedLiteral()
);
for (let pathIdx = 0; pathIdx < resultPaths.length; pathIdx++) {
const currentType = resultPaths[pathIdx][varIdx - 1].type;
let currentTypeName: string = '';
if (currentType) {
currentTypeName = ((currentType as arkts.ETSTypeReference).part.name as arkts.Identifier).name;
}
if (currentType && currentTypeName !== 'String') {
const assignementRightExpr = factory.createUnionTypeAssignmentExpr(resultPaths[pathIdx][varIdx].segment);
elseBranch = factory.createInstanceOfBranch(currentTypeName, assignementRightExpr, elseBranch);
}
}
blocks.push(elseBranch);
}
blocks.push(arkts.factory.createReturnStatement(arkts.factory.createIdentifier('x')));
return blocks;
}
* create IMonitorPathsInfo type parameter `{ path: "<monitorItem>", lambda: () => { return this.<monitorItem> } }`.
*
* @param monitorItem monitored property name.
*/
private static createMonitorPathProperties(
monitorItem: string,
hasWildcard: boolean,
blocks: arkts.Statement[]
): arkts.Property[] {
const properties: arkts.Property[] = [
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.PATH),
arkts.factory.createStringLiteral(monitorItem),
false,
false
),
];
if (hasWildcard) {
properties.push(arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MONITOR_WILDCARD_PROPERTY_NAME),
arkts.factory.createBooleanLiteral(true),
false,
false
));
}
properties.push(arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.VALUE_CALLBACK),
arkts.factory.createArrowFunctionExpression(
UIFactory.createScriptFunction({
flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
body: arkts.factory.createBlockStatement(blocks),
returnTypeAnnotation: UIFactory.createTypeReferenceFromString(TypeNames.ANY),
})
),
false,
false
));
return properties;
}
static createMonitorPathsInfoParameter(
monitorItem: string,
definition?: arkts.ClassDefinition
): arkts.ObjectExpression {
const compatibleVersion = MetaDataCollector.getInstance().projectConfig?.compatibleSdkVersion;
const hasWildcard: boolean = monitorItem.endsWith(MONITOR_WILDCARD_SUFFIX) &&
compatibleVersion !== undefined && compatibleVersion >= MONITOR_WILDCARD_MIN_VERSION;
const propertyPathResult = definition ?
factory.findUnionTypesInPropertyPath(definition, monitorItem, hasWildcard) : undefined;
const valueCallbackPath: string = hasWildcard
? monitorItem.substring(0, monitorItem.length - MONITOR_WILDCARD_SUFFIX.length)
: monitorItem;
const itemNameSplit: string[] = valueCallbackPath.split('.');
let blocks: arkts.Statement[] = [];
if (propertyPathResult === undefined) {
let monitorVariable: arkts.Expression = arkts.factory.createUndefinedLiteral();
if (itemNameSplit.length > 0 && itemNameSplit[0] !== '') {
monitorVariable = this.generateMonitorVariable(itemNameSplit);
}
blocks.push(arkts.factory.createReturnStatement(monitorVariable));
} else {
blocks.push(...factory.generateUnionTypePathBlocks(propertyPathResult, itemNameSplit));
}
return arkts.factory.createObjectExpression(
this.createMonitorPathProperties(monitorItem, hasWildcard, blocks)
);
}
private static createUnionTypeAssignmentExpr(segment: string): arkts.Expression {
if (isNumeric(segment)) {
return arkts.factory.createCallExpression(
arkts.factory.createMemberExpression(
arkts.factory.createIdentifier('x'),
arkts.factory.createIdentifier('$_get'),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, false, false),
[arkts.factory.createNumberLiteral(Number(segment))], undefined, false, false);
}
return arkts.factory.createMemberExpression(
arkts.factory.createIdentifier('x'),
arkts.factory.createIdentifier(segment),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, false, false);
}
private static createInstanceOfBranch(
currentTypeName: string,
assignementRightExpr: arkts.Expression,
elseBranch: arkts.Statement
): arkts.IfStatement {
return arkts.factory.createIfStatement(
arkts.factory.createBinaryExpression(
arkts.factory.createIdentifier('x'),
UIFactory.createTypeReferenceFromString(currentTypeName),
arkts.Es2pandaTokenType.TOKEN_TYPE_KEYW_INSTANCEOF
),
arkts.factory.createBlockStatement([
arkts.factory.createExpressionStatement(
arkts.factory.createAssignmentExpression(
arkts.factory.createIdentifier('x'),
assignementRightExpr,
arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION
)
)
]),
elseBranch
);
}
static generateComputedOwnerAssignment(newName: string): arkts.ExpressionStatement {
const computedVariable = UIFactory.generateMemberExpression(
arkts.factory.createThisExpression(),
newName,
false
);
const setOwnerFunc = UIFactory.generateMemberExpression(
computedVariable,
StateManagementTypes.SET_OWNER,
false
);
return arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(setOwnerFunc, [arkts.factory.createThisExpression()], undefined, false, false)
);
}
static createResetOnReuseStmt(newName: string, arg?: arkts.Expression): arkts.ExpressionStatement {
const callee = arkts.factory.createMemberExpression(
generateThisBacking(newName, false, true),
arkts.factory.createIdentifier(StateManagementTypes.RESET_ON_REUSE),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
);
return arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(callee, arg ? [arg] : [], undefined, false, false)
);
}
static createResetOnReuseStmtWithArgs(newName: string, args: arkts.Expression[]): arkts.ExpressionStatement {
const callee = arkts.factory.createMemberExpression(
generateThisBacking(newName, false, true),
arkts.factory.createIdentifier(StateManagementTypes.RESET_ON_REUSE),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
);
return arkts.factory.createExpressionStatement(
arkts.factory.createCallExpression(callee, args, undefined, false, false)
);
}
static generateSyncMonitorAssignment(
monitorItem: string[] | undefined,
originalName: string,
newName: string,
isFromStruct: boolean,
paramsLength: number,
definition?: arkts.ClassDefinition
): arkts.ExpressionStatement {
if (paramsLength === 0) {
collectStateManagementTypeImport(StateManagementTypes.I_MONITOR);
}
const thisValue: arkts.Expression = generateThisBacking(newName, false, false);
const args: arkts.Expression[] = [this.generateSyncMonitorPathArg(monitorItem, definition), this.generateLambdaArg(originalName, paramsLength)];
const makeSyncMonitorOptions = arkts.factory.createObjectExpression([
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier('owner'),
isFromStruct ? arkts.factory.createThisExpression() : arkts.factory.createUndefinedLiteral(),
false,
false
),
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier('functionName'),
arkts.factory.createStringLiteral(originalName),
false,
false
)
]);
args.push(makeSyncMonitorOptions);
const right: arkts.CallExpression = factory.generateStateMgmtFactoryCall(
StateManagementTypes.MAKE_SYNC_MONITOR,
undefined,
args,
false
);
return arkts.factory.createExpressionStatement(
arkts.factory.createAssignmentExpression(
thisValue,
right,
arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION
)
);
}
static generateSyncMonitorPathArg(monitorItem: string[] | undefined,
definition?: arkts.ClassDefinition): arkts.ArrayExpression {
if (!monitorItem || monitorItem.length <= 0) {
return arkts.factory.createArrayExpression([]);
}
const params = monitorItem.map((itemName: string) => {
return factory.createSyncMonitorPathsInfoParameter(itemName, definition);
});
return arkts.factory.createArrayExpression(params);
}
static createSyncMonitorPathsInfoParameter(
monitorItem: string,
definition?: arkts.ClassDefinition
): arkts.ObjectExpression {
const hasWildcard: boolean = monitorItem.endsWith(MONITOR_WILDCARD_SUFFIX);
const valueCallbackPath: string = hasWildcard
? monitorItem.substring(0, monitorItem.length - MONITOR_WILDCARD_SUFFIX.length)
: monitorItem;
const itemNameSplit: string[] = valueCallbackPath.split('.');
const propertyPathResult = definition ?
factory.findUnionTypesInPropertyPath(definition, monitorItem, hasWildcard) : undefined;
let blocks: arkts.Statement[] = [];
if (propertyPathResult === undefined) {
let monitorVariable: arkts.Expression = arkts.factory.createUndefinedLiteral();
if (itemNameSplit.length > 0 && itemNameSplit[0] !== '') {
monitorVariable = this.generateMonitorVariable(itemNameSplit);
}
blocks.push(arkts.factory.createReturnStatement(monitorVariable));
} else {
blocks.push(...factory.generateUnionTypePathBlocks(propertyPathResult, itemNameSplit));
}
const properties: arkts.Property[] = [
arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.PATH),
arkts.factory.createStringLiteral(monitorItem),
false,
false
),
];
if (hasWildcard) {
properties.push(arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MONITOR_WILDCARD_PROPERTY_NAME),
arkts.factory.createBooleanLiteral(true),
false,
false
));
}
properties.push(arkts.factory.createProperty(
arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT,
arkts.factory.createIdentifier(MonitorNames.VALUE_CALLBACK),
arkts.factory.createArrowFunctionExpression(
UIFactory.createScriptFunction({
flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW,
body: arkts.factory.createBlockStatement(blocks),
returnTypeAnnotation: UIFactory.createTypeReferenceFromString(TypeNames.ANY),
})
),
false,
false
));
return arkts.factory.createObjectExpression(properties);
}
static stringLiteralToMemberExpression(node: arkts.Expression): arkts.Expression {
if (!arkts.isStringLiteral(node)) {
return node;
}
const parts: string[] = node.str.split('.');
if (parts.length !== 2) {
return node;
}
return arkts.factory.createMemberExpression(
arkts.factory.createIdentifier(parts[0]),
arkts.factory.createIdentifier(parts[1]),
arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
false,
false
);
}
}