From dc267ec50f08c89d9588fd6b97e69a85c106066f Mon Sep 17 00:00:00 2001 From: Yuxin Feng Date: Sun, 25 May 2025 16:19:07 +0800 Subject: [PATCH] uiplugin @AnimatableExtend transform Signed-off-by: Yuxin Feng Change-Id: I7df80a4386f6d46bb5e9f33cad7c88b530621000 --- arkui-plugins/common/predefines.ts | 9 +- .../ui-plugins/checked-transformer.ts | 28 ++- .../ui-plugins/property-translators/utils.ts | 5 +- .../ui-plugins/struct-translators/factory.ts | 193 ++++++++++++++++-- 4 files changed, 214 insertions(+), 21 deletions(-) diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index d4667b424..181a9d50d 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -38,7 +38,7 @@ export const EXTERNAL_SOURCE_ALLOWED_IMPORT_INSERT_NAMES: string[] = [ ]; export const IMPORT_SOURCE_MAP: Map> = new Map>([ - ['@ohos.arkui.component', new Set(['$r', '$rawfile', '_r', '_rawfile', 'Bindable'])], + ['@ohos.arkui.component', new Set(['$r', '$rawfile', '_r', '_rawfile', 'Bindable', 'AnimatableArithmetic'])], [ '@ohos.arkui.stateManagement', new Set([ @@ -77,11 +77,11 @@ export const IMPORT_SOURCE_MAP: Map> = new Map = new Map([ @@ -100,6 +100,7 @@ export const OUTPUT_DEPENDENCY_MAP: Map = new Map { + const updatedBody = node.definition.body.map((member: arkts.AstNode) => { if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.BUILDER)) { member.scriptFunction.setAnnotations([annotation('memo')]); } + if(arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.ANIMATABLE_EXTEND)){ + member = arkts.factory.updateMethodDefinition( + member, + member.kind, + member.name, + arkts.factory.createFunctionExpression(structFactory.transformAnimatableExtend(member.scriptFunction)), + member.modifiers, + false + ) + } return member; }); - return node; + return arkts.factory.updateClassDeclaration( + node, + arkts.factory.updateClassDefinition( + node.definition, + node.definition.ident, + node.definition.typeParams, + node.definition.superTypeParams, + node.definition.implements, + undefined, + node.definition.super, + updatedBody, + node.definition.modifiers, + arkts.classDefinitionFlags(node.definition) + ) + ); } /** diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 9005d8d88..60dc5a41c 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -34,7 +34,8 @@ export enum DecoratorNames { LOCAL_STORAGE_PROP = 'LocalStorageProp', LOCAL_STORAGE_LINK = 'LocalStorageLink', REUSABLE = 'Reusable', - TRACK = 'Track' + TRACK = 'Track', + ANIMATABLE_EXTEND = 'AnimatableExtend' } export function collectPropertyDecorators(property: arkts.ClassProperty): string[] { @@ -52,7 +53,7 @@ export function isDecoratorAnnotation(anno: arkts.AnnotationUsage, decoratorName } export function hasDecorator( - property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition | arkts.ScriptFunction, decoratorName: DecoratorNames ): boolean { if (arkts.isMethodDefinition(property)) { diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 918d2ebac..5a2caa43b 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -276,14 +276,18 @@ export class factory { } /* - * add headers for animation in UICommonMethod + * add headers for animation & @AnimatableExtend in UICommonMethod */ static modifyExternalComponentCommon(node: arkts.TSInterfaceDeclaration): arkts.AstNode { const animationStart = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_START); const animationStop = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_STOP); + const AniPropertyNum = factory.createOrSetAniProperty(true); + const AniPropertyArithmetic = factory.createOrSetAniProperty(false); const updatedBody = arkts.factory.updateInterfaceBody(node.body!, [ animationStart, animationStop, + AniPropertyNum, + AniPropertyArithmetic, ...node.body!.body, ]); return arkts.factory.updateInterfaceDeclaration( @@ -298,21 +302,97 @@ export class factory { } /* - * generate animationStart(...) and animationStop(...) + * helper to create value parameter for AnimatableExtend methods + */ + static createAniExtendValueParam(isNumber: boolean): arkts.ETSParameterExpression { + const numberType = arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('number')) + ); + const AnimatableArithmeticType = arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier('AnimatableArithmetic'), + arkts.factory.createTSTypeParameterInstantiation([ + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('T')) + ), + ]) + ) + ); + return arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier('value', isNumber ? numberType : AnimatableArithmeticType), + undefined + ); + } + + /* + * generate __createOrSetAnimatableProperty(...) for AnimatableExtend + */ + static createOrSetAniProperty(isNumber: boolean): arkts.MethodDefinition { + const funcNameParam: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + 'functionName', + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('string')) + ) + ), + undefined + ); + const cbParam = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + 'callback', + arkts.factory.createFunctionType( + arkts.factory.createFunctionSignature( + undefined, + [factory.createAniExtendValueParam(isNumber)], + arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false + ), + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW + ) + ), + undefined + ); + const funcSig = arkts.factory.createFunctionSignature( + isNumber + ? undefined + : arkts.factory.createTypeParameterDeclaration( + [arkts.factory.createTypeParameter(arkts.factory.createIdentifier('T'))], + 0 + ), + [funcNameParam, factory.createAniExtendValueParam(isNumber), cbParam], + arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false + ); + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + arkts.factory.createIdentifier('__createOrSetAnimatableProperty'), + arkts.factory.createFunctionExpression( + arkts.factory.createScriptFunction( + undefined, + funcSig, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + } + + /* + * generate animationStart(...) and animationStop(...) for animation */ static createAnimationMethod(key: string): arkts.MethodDefinition { const aniparams: arkts.Expression[] = [ arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier( 'value', - arkts.factory.createUnionType( - [ - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('AnimateParam')) - ), - arkts.factory.createETSUndefinedType() - ] - ) + arkts.factory.createUnionType([ + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('AnimateParam')) + ), + arkts.factory.createETSUndefinedType(), + ]) ), undefined ), @@ -342,9 +422,7 @@ export class factory { arkts.factory.createIdentifier( 'packageInfo', arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('string') - ) + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('string')) ) ), undefined @@ -384,4 +462,93 @@ export class factory { } return node; } + + /* + * helper for transformAnimatableExtend to create callback argument in __createAnimatableProperty + */ + static createAniExtendCbArg( + param: arkts.ETSParameterExpression, + originStatements: arkts.Statement[] + ): arkts.ArrowFunctionExpression { + const isNumberType = + param.type && + arkts.isETSTypeReference(param.type) && + param.type.part && + param.type.part.name && + arkts.isIdentifier(param.type.part.name) && + param.type.part.name.name === 'number'; + const assignmentExpr = arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + param.identifier.clone(), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + arkts.factory.createTSAsExpression(param.identifier.clone(), param.type as arkts.TypeNode, false) + ) + ); + const AniArithmeticParam = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + param.identifier.name, + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier('AnimatableArithmetic'), + arkts.factory.createTSTypeParameterInstantiation([param.type as arkts.TypeNode]) + ) + ) + ), + undefined + ); + return arkts.factory.createArrowFunction( + arkts.factory.createScriptFunction( + arkts.factory.createBlock([...(isNumberType ? [] : [assignmentExpr]), ...originStatements]), + arkts.factory.createFunctionSignature( + undefined, + isNumberType ? [param.clone()] : [AniArithmeticParam], + undefined, + false + ), + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ) + ); + } + + /* + * transform @AnimatableExtend method + */ + static transformAnimatableExtend(node: arkts.ScriptFunction): arkts.ScriptFunction { + if (!arkts.isEtsParameterExpression(node.params[1]) || !node.body || !arkts.isBlockStatement(node.body)) { + return node; + } + const funcName: arkts.StringLiteral = arkts.factory.createStringLiteral(node.id?.name!); + const paramValue: arkts.ETSParameterExpression = node.params[1]; + const originStatements: arkts.Statement[] = [...node.body.statements]; + const createOrSetStatement = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier('__createOrSetAnimatableProperty'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + undefined, + [ + funcName, + paramValue.identifier, + factory.createAniExtendCbArg(paramValue, originStatements.slice(0, -1)), + ] + ) + ); + return arkts.factory.updateScriptFunction( + node, + arkts.factory.createBlock([createOrSetStatement, originStatements[originStatements.length - 1]]), + arkts.FunctionSignature.createFunctionSignature( + node.typeParams, + node.params, + node.returnTypeAnnotation, + node.hasReceiver + ), + node.flags, + node.modifiers + ); + } } -- Gitee