From 6c8a0cd7bfe8030c101c1a7fc8920fbe40cd4753 Mon Sep 17 00:00:00 2001 From: Yuxin Feng Date: Thu, 5 Jun 2025 20:24:56 +0800 Subject: [PATCH] most up to date animatableextend transform Signed-off-by: Yuxin Feng Change-Id: Ib1f2dcab5ff26786ac8bfcea586917b17b558fe6 --- arkui-plugins/common/predefines.ts | 11 ++ .../builder-lambda-translators/factory.ts | 8 +- .../ui-plugins/struct-translators/factory.ts | 185 +++++++++++++++++- arkui-plugins/ui-plugins/utils.ts | 5 +- 4 files changed, 193 insertions(+), 16 deletions(-) diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index 8825a0df1..7aa7f645d 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -71,6 +71,7 @@ export enum DecoratorNames { LOCAL_STORAGE_LINK = 'LocalStorageLink', REUSABLE = 'Reusable', TRACK = 'Track', + ANIMATABLE_EXTEND = 'AnimatableExtend' } export enum DecoratorIntrinsicNames { @@ -113,6 +114,14 @@ export enum StateManagementTypes { MAKE_MUTABLESTATE_META = 'makeMutableStateMeta', } +export enum AnimationNames { + ANIMATABLE_ARITHMETIC = 'AnimatableArithmetic', + CREATE_OR_SET_ANIMATABLEPROPERTY = '__createOrSetAnimatableProperty', + ANIMATION = 'animation', + ANIMATION_START = 'animationStart', + ANIMATION_STOP = 'animationStop', +} + export const DECORATOR_TYPE_MAP = new Map([ [DecoratorNames.STATE, StateManagementTypes.STATE_DECORATED], [DecoratorNames.LINK, StateManagementTypes.LINK_SOURCE_TYPE], @@ -179,6 +188,7 @@ export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map = new Map [StateManagementTypes.STORAGE_LINK_STATE, 'arkui.stateManagement.runtime'], [StateManagementTypes.OBSERVABLE_PROXY, 'arkui.stateManagement.runtime'], [StateManagementTypes.PROP_STATE, 'arkui.stateManagement.runtime'], + [AnimationNames.ANIMATABLE_ARITHMETIC, 'arkui.component.common'] ]); export enum GetSetTypes { diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index 99b1a6cf8..a9177f4ef 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -45,7 +45,7 @@ import { import { isDecoratorIntrinsicAnnotation } from '../property-translators/utils'; import { factory as PropertyFactory } from '../property-translators/factory'; import { ProjectConfig } from '../../common/plugin-context'; -import { BindableDecl, DecoratorIntrinsicNames, StructDecoratorNames } from '../../common/predefines'; +import { AnimationNames, BindableDecl, DecoratorIntrinsicNames, StructDecoratorNames } from '../../common/predefines'; import { ImportCollector } from '../../common/import-collector'; export class factory { @@ -569,14 +569,14 @@ export class factory { continue; } const property: arkts.Identifier = instanceCalls[curIdx].call.expression as arkts.Identifier; - if (property.name === BuilderLambdaNames.ANIMATION_NAME) { + if (property.name === AnimationNames.ANIMATION) { const aniStart: arkts.CallExpression = arkts.factory.createCallExpression( - arkts.factory.createIdentifier(BuilderLambdaNames.ANIMATION_START), + arkts.factory.createIdentifier(AnimationNames.ANIMATION_START), undefined, instanceCalls[curIdx].call.arguments ); const aniStop: arkts.CallExpression = arkts.factory.createCallExpression( - arkts.factory.createIdentifier(BuilderLambdaNames.ANIMATION_STOP), + arkts.factory.createIdentifier(AnimationNames.ANIMATION_STOP), undefined, instanceCalls[curIdx].call.arguments.map((arg) => arg.clone()) ); diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 91223e88e..3eed150d6 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; import { - BuilderLambdaNames, addMemoAnnotation, CustomComponentNames, getCustomComponentOptionsName, @@ -42,6 +41,7 @@ import { ProjectConfig } from '../../common/plugin-context'; import { DeclarationCollector } from '../../common/declaration-collector'; import { ImportCollector } from '../../common/import-collector'; import { + AnimationNames, ARKUI_COMPONENT_COMMON_SOURCE_NAME, DecoratorNames, Dollars, @@ -297,14 +297,16 @@ export class factory { } /* - * add headers for animation in CommonMethod + * add headers for animation & @AnimatableExtend in CommonMethod */ static modifyExternalComponentCommon(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { - const animationStart = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_START); - const animationStop = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_STOP); + const animationStart = factory.createAnimationMethod(AnimationNames.ANIMATION_START); + const animationStop = factory.createAnimationMethod(AnimationNames.ANIMATION_STOP); + const createOrSetAniProperty = factory.createOrSetAniProperty(); const updatedBody = arkts.factory.updateInterfaceBody(node.body!, [ animationStart, animationStop, + createOrSetAniProperty, ...node.body!.body, ]); return arkts.factory.updateInterfaceDeclaration( @@ -318,6 +320,69 @@ export class factory { ); } + /* + * helper to create value parameter for AnimatableExtend methods + */ + static createAniExtendValueParam(): arkts.ETSParameterExpression { + const numberType = uiFactory.createTypeReferenceFromString('number'); + const AnimatableArithmeticType = arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(AnimationNames.ANIMATABLE_ARITHMETIC), + arkts.factory.createTSTypeParameterInstantiation([uiFactory.createTypeReferenceFromString('T')]) + ) + ); + return arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + 'value', + arkts.factory.createUnionType([numberType, AnimatableArithmeticType]) + ), + undefined + ); + } + + /* + * generate __createOrSetAnimatableProperty(...) for AnimatableExtend + */ + static createOrSetAniProperty(): arkts.MethodDefinition { + const funcNameParam: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier('functionName', uiFactory.createTypeReferenceFromString('string')), + undefined + ); + const cbParam = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + 'callback', + arkts.factory.createFunctionType( + arkts.factory.createFunctionSignature( + undefined, + [factory.createAniExtendValueParam()], + arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false + ), + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW + ) + ), + undefined + ); + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + arkts.factory.createIdentifier(AnimationNames.CREATE_OR_SET_ANIMATABLEPROPERTY), + uiFactory.createScriptFunction({ + typeParams: arkts.factory.createTypeParameterDeclaration( + [arkts.factory.createTypeParameter(arkts.factory.createIdentifier('T'))], + 0 + ), + params: [funcNameParam, factory.createAniExtendValueParam(), cbParam], + returnTypeAnnotation: arkts.factory.createPrimitiveType( + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID + ), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + }), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + } + /* * generate animationStart(...) and animationStop(...) */ @@ -519,11 +584,35 @@ export class factory { return node; } if (isEtsGlobalClass(node)) { - node.definition.body.forEach( - (member: arkts.AstNode) => - arkts.isMethodDefinition(member) && propertyFactory.addMemoToBuilderClassMethod(member) + const updatedBody = node.definition.body.map((member: arkts.AstNode) => { + arkts.isMethodDefinition(member) && propertyFactory.addMemoToBuilderClassMethod(member); + if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.ANIMATABLE_EXTEND)) { + member = arkts.factory.updateMethodDefinition( + member, + member.kind, + member.name, + factory.transformAnimatableExtend(member.scriptFunction), + member.modifiers, + false + ); + } + return member; + }); + 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) + ) ); - return node; } const newClassDef = factory.updateObservedTrackClassDef(node.definition); return arkts.factory.updateClassDeclaration(node, newClassDef); @@ -610,4 +699,84 @@ export class factory { ...classScopeInfo.getters, ]; } + + /* + * helper for transformAnimatableExtend to create callback argument in __createAnimatableProperty + */ + static createAniExtendCbArg( + param: arkts.ETSParameterExpression, + originStatements: arkts.Statement[] + ): arkts.ArrowFunctionExpression { + 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 numberType = uiFactory.createTypeReferenceFromString('number'); + const AnimatableArithmeticType = arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(AnimationNames.ANIMATABLE_ARITHMETIC), + arkts.factory.createTSTypeParameterInstantiation([param.type as arkts.TypeNode]) + ) + ); + ImportCollector.getInstance().collectImport(AnimationNames.ANIMATABLE_ARITHMETIC); + return arkts.factory.createArrowFunction( + uiFactory.createScriptFunction({ + body: arkts.factory.createBlock([assignmentExpr, ...originStatements]), + params: [ + arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + param.identifier.name, + arkts.factory.createUnionType([numberType, AnimatableArithmeticType]) + ), + undefined + ), + ], + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + }) + ); + } + + /* + * 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(AnimationNames.CREATE_OR_SET_ANIMATABLEPROPERTY), + 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 + ); + } } diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index d23949753..e66bf494d 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -38,10 +38,7 @@ export enum BuilderLambdaNames { TRANSFORM_METHOD_NAME = '_instantiateImpl', STYLE_PARAM_NAME = 'style', STYLE_ARROW_PARAM_NAME = 'instance', - CONTENT_PARAM_NAME = 'content', - ANIMATION_NAME = 'animation', - ANIMATION_START = 'animationStart', - ANIMATION_STOP = 'animationStop', + CONTENT_PARAM_NAME = 'content' } export enum MemoNames { -- Gitee