diff --git a/.gitee/CODEOWNERS b/.gitee/CODEOWNERS index 281eab68d9b64f78de571883239f185323e687b2..5419e82c8a6b57a7fd06c35c69736cc9abf43e55 100755 --- a/.gitee/CODEOWNERS +++ b/.gitee/CODEOWNERS @@ -26,7 +26,7 @@ compiler/test/ut/ @lixingchi1 compiler/test/utForPartialUpdate/ @lixingchi1 compiler/test/utForValidate/ @lixingchi1 compiler/test/transform_ut/ @lixingchi1 -koala-wrapper/ @VictorS67 +koala-wrapper/ @VictorS67 @youzhi92 # Code owners for ArkCompiler ace_ets2bundle diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index fa1e5621a539890a0393ff707e247e70b8ec33b0..366b8f42ec1d2d77fe00f92e66dc8ad1e7a215c3 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -257,6 +257,10 @@ export enum ConditionNames { CONDITION_BRANCH = 'ConditionBranch', } +export enum ArkTsDefaultNames { + DEFAULT_STATIC_BLOCK_NAME = '', +} + export const RESOURCE_TYPE: Record = { color: 10001, float: 10002, diff --git a/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets b/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets index 51836622cb772e4521c71243f55e6e60103442a9..55efc5b71886fb52ab0bebcb596ad8be327525c7 100644 --- a/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets +++ b/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets @@ -40,3 +40,26 @@ struct Parent { build() {} } + +@ComponentV2 +struct Parent2 { + @Computed + static get fullName(): string { + return Name.firstName + ' ' + Name.lastName; + } + + @Computed + static get fullName2(): string { + return Parent.localVar1; + } + + build() {} +} + +@ObservedV2 +class Name2 { + @Computed + static get fullName(): string { + return Name.firstName + ' ' + Name.lastName; + } +} diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts index ae6a0e38b82b94d40222450bcb69bc8378e3adfb..2d7331ed63ae4cd279816b51c602f0c4a61d31eb 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts @@ -174,6 +174,72 @@ function main() {} } } +@ComponentV2() final struct Parent2 extends CustomComponentV2 { + public __initializeStruct(initializers: (__Options_Parent2 | undefined), @memo() content: ((()=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_Parent2 | undefined)): void {} + + public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + return ((((Name.firstName) + (" "))) + (Name.lastName)); + }), "fullName"); + + @Computed() public static get fullName(): string { + return Parent2.__computed_fullName.get(); + } + + public static __computed_fullName2 = STATE_MGMT_FACTORY.makeComputed((() => { + return Parent.localVar1; + }), "fullName2"); + + @Computed() public static get fullName2(): string { + return Parent2.__computed_fullName2.get(); + } + + @memo() public build() {} + + public constructor() {} + + static { + + } +} + +@ObservedV2() class Name2 implements IObservedObject, ISubscribedWatches { + @JSONStringifyIgnore() private subscribedWatches: ISubscribedWatches = STATE_MGMT_FACTORY.makeSubscribedWatches(); + + public addWatchSubscriber(watchId: WatchIdType): void { + this.subscribedWatches.addWatchSubscriber(watchId); + } + + public removeWatchSubscriber(watchId: WatchIdType): boolean { + return this.subscribedWatches.removeWatchSubscriber(watchId); + } + + public executeOnSubscribingWatches(propertyName: string): void { + this.subscribedWatches.executeOnSubscribingWatches(propertyName); + } + + public setV1RenderId(renderId: RenderIdType): void {} + + protected conditionalAddRef(meta: IMutableStateMeta): void { + meta.addRef(); + } + + public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + return ((((Name.firstName) + (" "))) + (Name.lastName)); + }), "fullName"); + + @Computed() public static get fullName(): string { + return Name2.__computed_fullName.get(); + } + + static { + + } + public constructor() {} + +} + @ComponentV2() export interface __Options_Parent { set localVar1(localVar1: (string | undefined)) @@ -188,6 +254,10 @@ function main() {} get __backing_localVar2(): (ILocalDecoratedVariable | undefined) +} + +@ComponentV2() export interface __Options_Parent2 { + } `; diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 664740cf1694453ba796cda49d1721e234a08190..13a120dc40a2bdfb6a5df38951de0d33b4e085bf 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -25,6 +25,7 @@ import { isCustomComponentInterface, isCustomDialogControllerOptions, isKnownMethodDefinition, + isStatic, } from '../utils'; import { factory as UIFactory } from '../ui-factory'; import { factory as PropertyFactory } from '../property-translators/factory'; @@ -57,6 +58,7 @@ import { findBuilderIndexInControllerOptions, ObservedAnnoInfo, getNoTransformationMembersInClass, + isComputedMethod, } from './utils'; import { collectStateManagementTypeImport, generateThisBacking, hasDecorator } from '../property-translators/utils'; import { ComponentAttributeCache, isComponentAttributeInterface } from '../builder-lambda-translators/utils'; @@ -517,18 +519,13 @@ export class factory { classOptionsName ?? getCustomComponentOptionsName(className), scope ); - const updateMembers: arkts.AstNode[] = definition.body - .filter( - (member) => - !arkts.isClassProperty(member) && - !(arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.COMPUTED)) - ) + const updateMembers: arkts.AstNode[] = body + .filter((member) => !arkts.isClassProperty(member) && !isComputedMethod(member)) .map((member: arkts.AstNode) => factory.transformNonPropertyMembersInClass(member, scope.isDecl)); - - const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass(definition, [ - ...translatedMembers, - ...updateMembers, - ]); + const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass( + definition, + factory.addClassStaticBlock([...translatedMembers, ...updateMembers], body) + ); if ( !!scope.annotations.customdialog || (scope.isDecl && scope.name === CustomComponentNames.BASE_CUSTOM_DIALOG_NAME) @@ -538,6 +535,21 @@ export class factory { return arkts.factory.updateClassDeclaration(node, updateClassDef); } + /** + * Determine whether a class static block needs to be added. + */ + static addClassStaticBlock(members: arkts.AstNode[], body: readonly arkts.AstNode[]): arkts.AstNode[] { + const staticBlock = body.find((item: arkts.AstNode) => arkts.isClassStaticBlock(item)); + if (staticBlock) { + return members; + } + const classHasStaticComputed = body.find((item: arkts.AstNode) => isComputedMethod(item) && isStatic(item)); + if (classHasStaticComputed) { + members.push(UIFactory.createClassStaticBlock()); + } + return members; + } + /** * add `__setDialogController__` method in `@CustomDialog` component. */ @@ -936,21 +948,25 @@ export class factory { className: ObservedAnno.className, getters: getters, }; + const body: readonly arkts.AstNode[] = definition.body; const translators: (ObservedTranslator | MethodTranslator)[] = filterDefined( - definition.body.map((it) => classifyInObservedClass(it, classScopeInfo)) + body.map((it) => classifyInObservedClass(it, classScopeInfo)) ); const metaProperty: arkts.ClassProperty[] = ObservedAnno.classHasTrack ? [] : [PropertyFactory.createMetaInObservedClass()]; const propertyMembers = translators.map((translator) => translator.translateMember()); const restMembers: arkts.AstNode[] = getNoTransformationMembersInClass(definition, ObservedAnno); - const returnNodes = [ - ...[...watchMembers, ...v1RenderIdMembers, conditionalAddRef], - ...(ObservedAnno.isObserved ? metaProperty : []), - ...collect(...propertyMembers), - ...restMembers, - ...classScopeInfo.getters, - ]; + const returnNodes = factory.addClassStaticBlock( + [ + ...[...watchMembers, ...v1RenderIdMembers, conditionalAddRef], + ...(ObservedAnno.isObserved ? metaProperty : []), + ...collect(...propertyMembers), + ...restMembers, + ...classScopeInfo.getters, + ], + body + ); return ObservedAnno.isObservedV2 ? returnNodes.concat(this.transformObservedV2Constuctor(definition, classScopeInfo.className)) : returnNodes; diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index ecba338d0f2218eb219efc9b0dbd8431ded149ac..1e32a07868894082c9a6d61ab206778c521dba9f 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -574,6 +574,10 @@ function isObjectAsExpression(param: arkts.AstNode): boolean { return arkts.isTSAsExpression(param) && !!param.expr && arkts.isObjectExpression(param.expr); } +export function isComputedMethod(node: arkts.AstNode): boolean { + return arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.COMPUTED); +} + export function findBuilderIndexInControllerOptions(properties: readonly arkts.Expression[]): number { return properties.findIndex((item: arkts.Expression) => { return ( diff --git a/arkui-plugins/ui-plugins/ui-factory.ts b/arkui-plugins/ui-plugins/ui-factory.ts index d850d67ae5cdc87c3d55134ce9b5fc624550dd4a..4ff604e44955187b2b4e0e0e3e080a53c47fef54 100644 --- a/arkui-plugins/ui-plugins/ui-factory.ts +++ b/arkui-plugins/ui-plugins/ui-factory.ts @@ -23,7 +23,7 @@ import { hasPropertyInAnnotation, } from './utils'; import { PartialExcept, PartialNested, PartialNestedExcept } from '../common/safe-types'; -import { DecoratorNames } from '../common/predefines'; +import { ArkTsDefaultNames, DecoratorNames } from '../common/predefines'; import { needDefiniteOrOptionalModifier } from './property-translators/utils'; import { addMemoAnnotation } from '../collectors/memo-collectors/utils'; @@ -477,4 +477,22 @@ export class factory { initializers ); } + + /** + * create class static block, e.g. `static {}`. + */ + static createClassStaticBlock(): arkts.ClassStaticBlock { + return arkts.factory.createClassStaticBlock( + arkts.factory.createFunctionExpression( + factory.createScriptFunction({ + key: arkts.factory.createIdentifier(ArkTsDefaultNames.DEFAULT_STATIC_BLOCK_NAME), + body: arkts.factory.createBlock([]), + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + flags: + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_STATIC_BLOCK | + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_EXPRESSION, + }) + ) + ); + } }