diff --git a/arkui-plugins/collectors/utils/collect-types.ts b/arkui-plugins/collectors/utils/collect-types.ts index 50240f9a3c3f44110ebff65637001f10732513fa..ace7ea54afa4cde791977f4dab98282b10c0515b 100644 --- a/arkui-plugins/collectors/utils/collect-types.ts +++ b/arkui-plugins/collectors/utils/collect-types.ts @@ -95,7 +95,7 @@ export interface ParameterRecord { isOptional: boolean; } -export function collectTypeRecordFromTypeParameterInstatiation( +export function collectTypeRecordFromTypeParameterInstantiation( typeParams: arkts.TSTypeParameterInstantiation | undefined ): TypeRecord[] | undefined { if (!typeParams) { @@ -202,7 +202,7 @@ export function collectTypeRecordFromTypeReference = new Array("xx", "yy", "zz"); - public constructor() {} - } @Component() final struct ImportStruct extends CustomComponent { @@ -82,7 +80,6 @@ class AB { public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} private __backing_arr?: Array; - public get arr(): Array { return (this.__backing_arr as Array); } @@ -106,47 +103,68 @@ class AB { instance.setColumnOptions(undefined).applyAttributesFinish(); return; }), @memo() (() => { - ForEach(((): Array => { - return this.arr; - }), ((item: string) => { - TextImpl(@memo() ((instance: TextAttribute): void => { - instance.setTextOptions(item, undefined).applyAttributesFinish(); - return; - }), undefined); - })); - ForEach(((): Array => { - return this.getArray(); - }), ((item: Person) => { - TextImpl(@memo() ((instance: TextAttribute): void => { - instance.setTextOptions(item.name, undefined).applyAttributesFinish(); - return; + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return this.arr; + }), @memo() ((item: string) => { + TextImpl(@memo() ((instance: TextAttribute): void => { + instance.setTextOptions(item, undefined).applyAttributesFinish(); + return; + }), undefined); }), undefined); + return; })); - ForEach(((): Array => { - return new AB().bar; - }), ((item: string) => { - TextImpl(@memo() ((instance: TextAttribute): void => { - instance.setTextOptions(item, undefined).applyAttributesFinish(); - return; + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return this.getArray(); + }), @memo() ((item: Person) => { + TextImpl(@memo() ((instance: TextAttribute): void => { + instance.setTextOptions(item.name, undefined).applyAttributesFinish(); + return; + }), undefined); }), undefined); + return; })); - ForEach(((): Array => { - return new AB().bar; - }), (() => {})); - ForEach(((): Array => { - return this.getArray(); - }), (() => {})); - ForEach(((): Array => { - return new Array("1", "2"); - }), (() => { - ForEach(((): Array => { - return new Array("1", "2"); - }), ((item: string) => { + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return new AB().bar; + }), @memo() ((item: string) => { TextImpl(@memo() ((instance: TextAttribute): void => { instance.setTextOptions(item, undefined).applyAttributesFinish(); return; }), undefined); - })); + }), undefined); + return; + })); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return new AB().bar; + }), @memo() (() => {}), undefined); + return; + })); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return this.getArray(); + }), @memo() (() => {}), undefined); + return; + })); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return new Array("1", "2"); + }), @memo() (() => { + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return new Array("1", "2"); + }), @memo() ((item: string) => { + TextImpl(@memo() ((instance: TextAttribute): void => { + instance.setTextOptions(item, undefined).applyAttributesFinish(); + return; + }), undefined); + }), undefined); + return; + })); + }), undefined); + return; })); })); } @@ -156,12 +174,10 @@ class AB { } @Component() export interface __Options_ImportStruct { - set arr(arr: (Array | undefined)) - get arr(): (Array | undefined) - set __options_has_arr(__options_has_arr: (boolean | undefined)) - + set arr(arr: (Array | undefined)) get __options_has_arr(): (boolean | undefined) + set __options_has_arr(__options_has_arr: (boolean | undefined)) } `; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts index 7077733f7f96533781edad4b1a02cfe374137dcb..76197b2c0ad11290daf4283d46e20a3b4a791de5 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts @@ -158,12 +158,16 @@ import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; - import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; import { ButtonImpl as ButtonImpl } from "arkui.component.button"; +import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; + +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; + import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; @@ -175,12 +179,9 @@ import { Param as Param, Require as Require, Local as Local } from "@ohos.arkui. function main() {} - class Region { public x: number; - public y: number; - public constructor(x: number, y: number) { this.x = x; this.y = y; @@ -190,11 +191,8 @@ class Region { class Info { public name: string; - public age: number; - public region: Region; - public constructor(name: string, age: number, x: number, y: number) { this.name = name; this.age = age; @@ -211,7 +209,6 @@ class Info { public __updateStruct(initializers: (__Options_Index | undefined)): void {} private __backing_infoList?: ILocalDecoratedVariable>; - public get infoList(): Array { return this.__backing_infoList!.get(); } @@ -225,15 +222,18 @@ class Info { instance.setColumnOptions(undefined).applyAttributesFinish(); return; }), @memo() (() => { - ForEach(((): Array => { - return this.infoList; - }), ((info: Info) => { - MiddleComponent._instantiateImpl(undefined, (() => { - return new MiddleComponent(); - }), { - info: info, - __options_has_info: true, - }, undefined, undefined); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return this.infoList; + }), @memo() ((info: Info) => { + MiddleComponent._instantiateImpl(undefined, (() => { + return new MiddleComponent(); + }), { + info: info, + __options_has_info: true, + }, undefined, undefined); + }), undefined); + return; })); ButtonImpl(@memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change", undefined).onClick(((e) => { @@ -263,7 +263,6 @@ class Info { } private __backing_info?: IParamDecoratedVariable; - public get info(): Info { return this.__backing_info!.get(); } @@ -307,7 +306,6 @@ class Info { } private __backing_region?: IParamDecoratedVariable; - public get region(): Region { return this.__backing_region!.get(); } @@ -329,41 +327,32 @@ class Info { } @ComponentV2() export interface __Options_Index { - set infoList(infoList: (Array | undefined)) - get infoList(): (Array | undefined) - set __backing_infoList(__backing_infoList: (ILocalDecoratedVariable> | undefined)) - + set infoList(infoList: (Array | undefined)) get __backing_infoList(): (ILocalDecoratedVariable> | undefined) - set __options_has_infoList(__options_has_infoList: (boolean | undefined)) - + set __backing_infoList(__backing_infoList: (ILocalDecoratedVariable> | undefined)) get __options_has_infoList(): (boolean | undefined) + set __options_has_infoList(__options_has_infoList: (boolean | undefined)) } @ComponentV2() export interface __Options_MiddleComponent { - set info(info: (Info | undefined)) - get info(): (Info | undefined) - @Require() set __backing_info(__backing_info: (IParamDecoratedVariable | undefined)) - + set info(info: (Info | undefined)) @Require() get __backing_info(): (IParamDecoratedVariable | undefined) - set __options_has_info(__options_has_info: (boolean | undefined)) - + @Require() set __backing_info(__backing_info: (IParamDecoratedVariable | undefined)) get __options_has_info(): (boolean | undefined) + set __options_has_info(__options_has_info: (boolean | undefined)) } @ComponentV2() export interface __Options_SubComponent { - set region(region: (Region | undefined)) - get region(): (Region | undefined) - @Require() set __backing_region(__backing_region: (IParamDecoratedVariable | undefined)) - + set region(region: (Region | undefined)) @Require() get __backing_region(): (IParamDecoratedVariable | undefined) - set __options_has_region(__options_has_region: (boolean | undefined)) - + @Require() set __backing_region(__backing_region: (IParamDecoratedVariable | undefined)) get __options_has_region(): (boolean | undefined) + set __options_has_region(__options_has_region: (boolean | undefined)) } `; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts index ba2ff24cfe84eec68cdb4072f57a2fe65b3a522d..21643ae7d0d9b7cc827aae59cff99f3fbf1ac8ed 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts @@ -40,6 +40,8 @@ const parsedTransform: Plugins = { const expectedCheckedScript: string = ` import { IConsumerDecoratedVariable as IConsumerDecoratedVariable } from "arkui.stateManagement.decorator"; +import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; + import { DividerAttribute as DividerAttribute } from "arkui.component.divider"; import { DividerImpl as DividerImpl } from "arkui.component.divider"; @@ -48,6 +50,8 @@ import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; +import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; + import { IProviderDecoratedVariable as IProviderDecoratedVariable } from "arkui.stateManagement.decorator"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; @@ -81,12 +85,11 @@ import { ComponentV2 as ComponentV2, DragEvent as DragEvent, Button as Button, C import { Provider as Provider, Consumer as Consumer, Local as Local, ObservedV2 as ObservedV2, Trace as Trace } from "@ohos.arkui.stateManagement"; const data: Array = [new User("Json", 10), new User("Eric", 15)]; - function main() {} + @ObservedV2() class User implements IObservedObject, ISubscribedWatches { @JSONStringifyIgnore() private subscribedWatches: ISubscribedWatches = STATE_MGMT_FACTORY.makeSubscribedWatches(); - public addWatchSubscriber(watchId: WatchIdType): void { this.subscribedWatches.addWatchSubscriber(watchId); } @@ -106,13 +109,9 @@ function main() {} } @JSONRename({newName:"name"}) private __backing_name?: string; - @JSONStringifyIgnore() private __meta_name: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"age"}) private __backing_age?: number; - @JSONStringifyIgnore() private __meta_age: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - public get name(): string { this.conditionalAddRef(this.__meta_name); return UIUtils.makeObserved((this.__backing_name as string)); @@ -154,7 +153,6 @@ function main() {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} private __backing_users?: IProviderDecoratedVariable>; - public get users(): Array { return this.__backing_users!.get(); } @@ -204,7 +202,6 @@ function main() {} public __updateStruct(initializers: (__Options_Child | undefined)): void {} private __backing_users?: IConsumerDecoratedVariable>; - public get users(): Array { return this.__backing_users!.get(); } @@ -218,26 +215,29 @@ function main() {} instance.setColumnOptions(undefined).applyAttributesFinish(); return; }), @memo() (() => { - ForEach(((): Array => { - return this.users; - }), ((item: User) => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { - instance.setColumnOptions(undefined).applyAttributesFinish(); - return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { - instance.setTextOptions(\`name: \${item.name}\`, undefined).fontSize(30).applyAttributesFinish(); - return; - }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { - instance.setTextOptions(\`age: \${item.age}\`, undefined).fontSize(30).applyAttributesFinish(); - return; - }), undefined); - DividerImpl(@memo() ((instance: DividerAttribute): void => { - instance.setDividerOptions().applyAttributesFinish(); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array => { + return this.users; + }), @memo() ((item: User) => { + ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + instance.setColumnOptions(undefined).applyAttributesFinish(); return; + }), @memo() (() => { + TextImpl(@memo() ((instance: TextAttribute): void => { + instance.setTextOptions(\`name: \${item.name}\`, undefined).fontSize(30).applyAttributesFinish(); + return; + }), undefined); + TextImpl(@memo() ((instance: TextAttribute): void => { + instance.setTextOptions(\`age: \${item.age}\`, undefined).fontSize(30).applyAttributesFinish(); + return; + }), undefined); + DividerImpl(@memo() ((instance: DividerAttribute): void => { + instance.setDividerOptions().applyAttributesFinish(); + return; + })); })); - })); + }), undefined); + return; })); })); } @@ -247,28 +247,22 @@ function main() {} } @ComponentV2() export interface __Options_Parent { - set users(users: (Array | undefined)) - get users(): (Array | undefined) - set __backing_users(__backing_users: (IProviderDecoratedVariable> | undefined)) - + set users(users: (Array | undefined)) get __backing_users(): (IProviderDecoratedVariable> | undefined) - set __options_has_users(__options_has_users: (boolean | undefined)) - + set __backing_users(__backing_users: (IProviderDecoratedVariable> | undefined)) get __options_has_users(): (boolean | undefined) + set __options_has_users(__options_has_users: (boolean | undefined)) } @ComponentV2() export interface __Options_Child { - set users(users: (Array | undefined)) - get users(): (Array | undefined) - set __backing_users(__backing_users: (IConsumerDecoratedVariable> | undefined)) - + set users(users: (Array | undefined)) get __backing_users(): (IConsumerDecoratedVariable> | undefined) - set __options_has_users(__options_has_users: (boolean | undefined)) - + set __backing_users(__backing_users: (IConsumerDecoratedVariable> | undefined)) get __options_has_users(): (boolean | undefined) + set __options_has_users(__options_has_users: (boolean | undefined)) } `; diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts index d77c2855f25014d7a21c18a9fa0233ee2f530596..53fb43fa8cfed6e73057a1269afd172f00c1eece 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts @@ -38,20 +38,22 @@ const parsedTransform: Plugins = { }; const expectedUIScript: string = ` -import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from \"arkui.stateManagement.decorator\"; -import { IStateDecoratedVariable as IStateDecoratedVariable } from \"arkui.stateManagement.decorator\"; -import { RowAttribute as RowAttribute } from \"arkui.component.row\"; +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; +import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; +import { RowAttribute as RowAttribute } from "arkui.component.row"; +import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; +import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.stateManagement.runtime"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; -import { TextAttribute as TextAttribute } from \"arkui.component.text\"; +import { memo as memo } from "arkui.stateManagement.runtime"; +import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; -import { NavInterface as NavInterface } from \"arkui.UserView\"; -import { PageLifeCycle as PageLifeCycle } from \"arkui.component.customComponent\"; -import { EntryPoint as EntryPoint } from \"arkui.UserView\"; -import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; -import { Builder as Builder, Text as Text, Color as Color, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Entry as Entry, Component as Component, Row as Row, ForEach as ForEach } from \"@ohos.arkui.component\"; -import { State as State } from \"@ohos.arkui.stateManagement\"; +import { NavInterface as NavInterface } from "arkui.UserView"; +import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent"; +import { EntryPoint as EntryPoint } from "arkui.UserView"; +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; +import { Builder as Builder, Text as Text, Color as Color, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Entry as Entry, Component as Component, Row as Row, ForEach as ForEach } from "@ohos.arkui.component"; +import { State as State } from "@ohos.arkui.stateManagement"; @memo() let globalBuilder: @Builder() ((value: string, size: number)=> void); let builderArr: Array<@Builder() ((value: string, size: number)=> void)>; function main() {} @@ -91,15 +93,18 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } @memo() public build() { RowImpl(@memo() ((instance: RowAttribute): void => { - instance.setRowOptions(undefined).height(\"100%\").applyAttributesFinish(); - return; + instance.setRowOptions(undefined).height("100%").applyAttributesFinish(); + return; }), @memo() (() => { - globalBuilder(this.message, 50); - ForEach(((): Array<@Builder() ((value: string, size: number)=> void)> => { - return builderArr; - }), ((@memo() item: @Builder() ((value: string, size: number)=> void)) => { - item(\"Hello World\", 30); - })); + globalBuilder.builder(this.message, 50); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array void)>> => { + return builderArr; + }), @memo() ((item: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>) => { + item.builder("Hello World", 30); + }), undefined); + return; + })); })); } public constructor() {} @@ -221,45 +226,57 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + RowImpl(__memo_context, ((__memo_id) + (136716185)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setRowOptions(undefined).height("100%").applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + globalBuilder.builder(__memo_context, ((__memo_id) + (76711614)), this.message, 50); + ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { - __memo_scope.cached; - return; + __memo_scope.cached; + return; } - __memo_parameter_instance.value.setRowOptions(undefined).height("100%").applyAttributesFinish(); - { - __memo_scope.recache(); - return; - } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); - if (__memo_scope.unchanged) { + __memo_parameter_instance.value.setForEachOptions(((): Array void)>> => { + return builderArr; + }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (223657391)), 1); + const __memo_parameter_item = __memo_scope.param(0, item); + if (__memo_scope.unchanged) { __memo_scope.cached; return; - } - globalBuilder(__memo_context, ((__memo_id) + ()), this.message, 50); - ForEach(__memo_context, ((__memo_id) + ()), ((): Array<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> => { - return builderArr; - }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() item: @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)) => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); - const __memo_parameter_item = __memo_scope.param(0, item); - if (__memo_scope.unchanged) { - __memo_scope.cached; - return; - } - __memo_parameter_item.value(__memo_context, ((__memo_id) + ()), \"Hello World\", 30); - { - __memo_scope.recache(); - return; - } - })); - { + } + item.builder(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); + { __memo_scope.recache(); return; - } - })); + } + }), undefined); + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + })); { __memo_scope.recache(); return; diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts index 332600aff0ec2f9e75fb340094e4bf540398ad4f..4b57f10241efcf2f642605585e0922410fe103bf 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts @@ -80,33 +80,42 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ pageFullPath: \"test/demo/mock/wrap-builder/wrap-builder-in-generic\", integratedHsp: \"false\", } as NavInterface)); -@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_message = STATE_MGMT_FACTORY.makeState(this, \"message\", ((({let gensym___ = initializers; - (((gensym___) == (null)) ? undefined : gensym___.message)})) ?? (\"Hello World\"))); - } - public __updateStruct(initializers: (__Options_Index | undefined)): void {} - private __backing_message?: IStateDecoratedVariable; - public get message(): string { - return this.__backing_message!.get(); - } - public set message(value: string) { - this.__backing_message!.set(value); - } - @memo() public build() { - RowImpl(@memo() ((instance: RowAttribute): void => { - instance.setRowOptions(undefined).height(\"100%\").applyAttributesFinish(); - return; - }), @memo() (() => { - globalBuilder.builder(this.message, 50); - ForEach(((): Array void)>> => { - return builderArr; - }), ((item: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>) => { - item.builder(\"Hello World\", 30); - })); - })); - } - public constructor() {} +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { + public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_message = STATE_MGMT_FACTORY.makeState(this, "message", ((({let gensym___117212394 = initializers; + (((gensym___117212394) == (null)) ? undefined : gensym___117212394.message)})) ?? ("Hello World"))); + } + + public __updateStruct(initializers: (__Options_Index | undefined)): void {} + + private __backing_message?: IStateDecoratedVariable; + public get message(): string { + return this.__backing_message!.get(); + } + + public set message(value: string) { + this.__backing_message!.set(value); + } + + @memo() public build() { + RowImpl(@memo() ((instance: RowAttribute): void => { + instance.setRowOptions(undefined).height("100%").applyAttributesFinish(); + return; + }), @memo() (() => { + globalBuilder.builder(this.message, 50); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array void)>> => { + return builderArr; + }), @memo() ((item: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>) => { + item.builder("Hello World", 30); + }), undefined); + return; + })); + })); + } + + public constructor() {} + } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { set message(message: (string | undefined)) @@ -214,70 +223,88 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ pageFullPath: \"test/demo/mock/wrap-builder/wrap-builder-in-generic\", integratedHsp: \"false\", } as NavInterface)); -@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { - this.__backing_message = STATE_MGMT_FACTORY.makeState(this, \"message\", ((({let gensym___ = initializers; - (((gensym___) == (null)) ? undefined : gensym___.message)})) ?? (\"Hello World\"))); - } - public __updateStruct(initializers: (__Options_Index | undefined)): void {} - private __backing_message?: IStateDecoratedVariable; - public get message(): string { - return this.__backing_message!.get(); - } - public set message(value: string) { - this.__backing_message!.set(value); +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { + public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + this.__backing_message = STATE_MGMT_FACTORY.makeState(this, "message", ((({let gensym___117212394 = initializers; + (((gensym___117212394) == (null)) ? undefined : gensym___117212394.message)})) ?? ("Hello World"))); + } + + public __updateStruct(initializers: (__Options_Index | undefined)): void {} + + private __backing_message?: IStateDecoratedVariable; + public get message(): string { + return this.__backing_message!.get(); + } + + public set message(value: string) { + this.__backing_message!.set(value); + } + + @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + const __memo_scope = __memo_context.scope(((__memo_id) + (135515930)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + RowImpl(__memo_context, ((__memo_id) + (136716185)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setRowOptions(undefined).height("100%").applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + globalBuilder.builder(__memo_context, ((__memo_id) + (76711614)), this.message, 50); + ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setForEachOptions(((): Array void)>> => { + return builderArr; + }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (223657391)), 1); + const __memo_parameter_item = __memo_scope.param(0, item); + if (__memo_scope.unchanged) { __memo_scope.cached; return; - } - RowImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); - const __memo_parameter_instance = __memo_scope.param(0, instance); - if (__memo_scope.unchanged) { - __memo_scope.cached; - return; - } - __memo_parameter_instance.value.setRowOptions(undefined).height(\"100%\").applyAttributesFinish(); - { - __memo_scope.recache(); - return; - } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); - if (__memo_scope.unchanged) { - __memo_scope.cached; - return; - } - globalBuilder.builder(__memo_context, ((__memo_id) + ()), this.message, 50); - ForEach(__memo_context, ((__memo_id) + ()), ((): Array void)>> => { - return builderArr; - }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); - const __memo_parameter_item = __memo_scope.param(0, item); - if (__memo_scope.unchanged) { - __memo_scope.cached; - return; - } - __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + ()), \"Hello World\", 30); - { - __memo_scope.recache(); - return; - } - })); - { - __memo_scope.recache(); - return; - } - })); - { + } + item.builder(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); + { __memo_scope.recache(); return; + } + }), undefined); + { + __memo_scope.recache(); + return; } + })); + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; } - public constructor() {} + } + + public constructor() {} + } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { set message(message: (string | undefined)) diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts index 79031740be3ab00e021f2dab0ac7e9920c29d55b..489c9efe92fba07ae7f3af4872784c2928d94e6e 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts @@ -81,10 +81,13 @@ function main() {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} @memo() public testBuilder() { - ForEach(((): Array> => { - return globalBuilderArr; - }), ((item: WrappedBuilder) => { - item.builder("hello world", 39); + ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + instance.setForEachOptions(((): Array> => { + return globalBuilderArr; + }), @memo() ((item: WrappedBuilder) => { + item.builder("hello world", 39); + }), undefined); + return; })); } @@ -192,21 +195,33 @@ function main() {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} @memo() public testBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { - const __memo_scope = __memo_context.scope(((__memo_id) + (194881372)), 0); + const __memo_scope = __memo_context.scope(((__memo_id) + (102938669)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ForEach(__memo_context, ((__memo_id) + (218979098)), ((): Array> => { - return globalBuilderArr; - }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder) => { - const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 1); - const __memo_parameter_item = __memo_scope.param(0, item); + ForEachImpl(__memo_context, ((__memo_id) + (223657391)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (218979098)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (46726221)), "hello world", 39); + __memo_parameter_instance.value.setForEachOptions(((): Array> => { + return globalBuilderArr; + }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 1); + const __memo_parameter_item = __memo_scope.param(0, item); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + item.builder(__memo_context, ((__memo_id) + (46726221)), "hello world", 39); + { + __memo_scope.recache(); + return; + } + }), undefined); { __memo_scope.recache(); return; @@ -219,13 +234,13 @@ function main() {} } @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { - const __memo_scope = __memo_context.scope(((__memo_id) + (142886843)), 0); + const __memo_scope = __memo_context.scope(((__memo_id) + (245938697)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (54078781)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { - const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + ColumnImpl(__memo_context, ((__memo_id) + (78055758)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (213687742)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -237,12 +252,12 @@ function main() {} return; } }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - const __memo_scope = __memo_context.scope(((__memo_id) + (213687742)), 0); + const __memo_scope = __memo_context.scope(((__memo_id) + (136716185)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - this.testBuilder(__memo_context, ((__memo_id) + (192802443))); + this.testBuilder(__memo_context, ((__memo_id) + (54078781))); { __memo_scope.recache(); return; diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..1914e30706611d20f2555f97f564f8b80e581e3c --- /dev/null +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts @@ -0,0 +1,141 @@ +/* + * 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 { checkIsTrailingLambdaInLastParam, isForEach } from '../utils'; +import { + collectTypeRecordFromParameter, + collectTypeRecordFromTypeParameterDeclaration, + collectTypeRecordFromTypeParameterInstantiation, + ParameterRecord, + TypeParameterTypeRecord, + TypeRecord, +} from '../../../collectors/utils/collect-types'; +import { factory as UIFactory } from '../../ui-factory'; + +export interface ComponentRecord { + name: string; + attributeRecords: ParameterRecord[]; + typeParams?: TypeParameterTypeRecord[]; + hasRestParameter?: boolean; + hasReceiver?: boolean; + hasLastTrailingLambda?: boolean; +} + +export class ComponentAttributeCache { + private _cache: Map; + private _attributeName: string | undefined; + private _attributeTypeParams: TypeRecord[] | undefined; + private _isCollected: boolean = false; + private static instance: ComponentAttributeCache; + + private constructor() { + this._cache = new Map(); + } + + static getInstance(): ComponentAttributeCache { + if (!this.instance) { + this.instance = new ComponentAttributeCache(); + } + return this.instance; + } + + private collectAttributeName(type: arkts.TypeNode | undefined): string | undefined { + if ( + !type || + !arkts.isETSTypeReference(type) || + !type.part || + !type.part.name || + !arkts.isIdentifier(type.part.name) + ) { + return; + } + this._attributeName = type.part.name.name; + if (type.part.typeParams) { + this._attributeTypeParams = collectTypeRecordFromTypeParameterInstantiation(type.part.typeParams); + } + } + + get attributeName(): string | undefined { + return this._attributeName; + } + + get attributeTypeParams(): TypeRecord[] | undefined { + return this._attributeTypeParams; + } + + reset(): void { + this._cache.clear(); + this._attributeName = undefined; + this._attributeTypeParams = undefined; + this._isCollected = false; + } + + isCollected(): boolean { + return this._isCollected; + } + + preprocessParam(param: arkts.ETSParameterExpression, index: number, name: string): arkts.ETSParameterExpression { + if (index === 0 && isForEach(name) && !!param.type && arkts.isTypeNode(param.type)) { + return arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + param.identifier.name, + UIFactory.createLambdaFunctionType([], param.type.clone()) + ), + undefined + ); + } + return param; + } + + collect(node: arkts.MethodDefinition): void { + this.collectAttributeName(node.scriptFunction.returnTypeAnnotation); + if (!this._attributeName) { + return; + } + const name: string = node.name.name; + const hasRestParameter = node.scriptFunction.hasRestParameter; + const hasReceiver = node.scriptFunction.hasReceiver; + const typeParams = collectTypeRecordFromTypeParameterDeclaration(node.scriptFunction.typeParams); + const params = node.scriptFunction.params as arkts.ETSParameterExpression[]; + const attributeRecords: ParameterRecord[] = []; + const hasLastTrailingLambda = checkIsTrailingLambdaInLastParam(params); + params.forEach((p, index) => { + if (index === params.length - 1 && hasLastTrailingLambda) { + return; + } + const record = collectTypeRecordFromParameter(this.preprocessParam(p, index, name)); + attributeRecords.push(record); + }); + const componentRecord: ComponentRecord = { + name, + attributeRecords, + typeParams, + hasRestParameter, + hasReceiver, + hasLastTrailingLambda, + }; + this._cache.set(name, componentRecord); + this._isCollected = true; + } + + getComponentRecord(name: string): ComponentRecord | undefined { + return this._cache.get(name); + } + + getAllComponentRecords(): ComponentRecord[] { + return Array.from(this._cache.values()); + } +} diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index bc5672c4c49dfa4b834e046119b09114049e99ee..6bffb9de5fcfd93f46ef6a760851c2a3faf93317 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -14,11 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; -import { - BuilderLambdaNames, - inferTypeFromValue, - optionsHasField, -} from '../utils'; +import { BuilderLambdaNames, inferTypeFromValue, optionsHasField } from '../utils'; import { backingField, filterDefined, @@ -54,8 +50,6 @@ import { BuilderLambdaStyleBodyInfo, getDeclaredSetAttribtueMethodName, checkIsTrailingLambdaInLastParam, - ComponentAttributeCache, - ComponentRecord, getTransformedComponentName, flatObjectExpressionToEntries, OptionsPropertyInfo, @@ -81,11 +75,15 @@ import { GenSymGenerator } from '../../common/gensym-generator'; import { addMemoAnnotation, checkIsMemoFromMemoableInfo, + collectMemoableInfoInFunctionReturnType, collectMemoableInfoInParameter, + collectScriptFunctionReturnTypeFromInfo, } from '../../collectors/memo-collectors/utils'; import { TypeRecord } from '../../collectors/utils/collect-types'; import { StyleInternalsVisitor } from './style-internals-visitor'; import { ConditionBreakCache } from './cache/conditionBreakCache'; +import { ComponentAttributeCache, ComponentRecord } from './cache/componentAttributeCache'; +import { isForEach } from './utils'; export class factory { /** @@ -98,7 +96,9 @@ export class factory { newName: string | undefined ): arkts.MethodDefinition { const func: arkts.ScriptFunction = node.scriptFunction; - const isFunctionCall: boolean = node.name.name !== BuilderLambdaNames.ORIGIN_METHOD_NAME; + const ident: arkts.Identifier = node.name; + const name: string = ident.name; + const isFunctionCall: boolean = name !== BuilderLambdaNames.ORIGIN_METHOD_NAME; const newParams: arkts.Expression[] = [...prefixArgs, ...func.params]; const updateFunc = arkts.factory .updateScriptFunction( @@ -118,7 +118,7 @@ export class factory { return arkts.factory.updateMethodDefinition( node, node.kind, - arkts.factory.updateIdentifier(node.name, newName ?? node.name.name), + arkts.factory.updateIdentifier(ident, newName ?? name), isFunctionCall ? updateFunc : addMemoAnnotation(updateFunc), node.modifiers, false @@ -533,7 +533,8 @@ export class factory { const memoableInfo = collectMemoableInfoInParameter(param); const canAddMemo = checkIsMemoFromMemoableInfo(memoableInfo, false); const fallback = arkts.factory.createUndefinedLiteral(); - modifiedArg = this.createOrUpdateArgInBuilderLambda(fallback, arg, canAddMemo, declInfo); + const updatedArg = this.createOrUpdateArgInBuilderLambda(fallback, arg, canAddMemo, declInfo); + modifiedArg = factory.processModifiedArg(updatedArg, index, leaf.arguments, moduleName, type?.name); } const shouldInsertToArgs = !isFunctionCall || (index === params.length - 1 && hasLastTrailingLambda); if (shouldInsertToArgs) { @@ -556,6 +557,64 @@ export class factory { return args; } + /** + * process `@ComponentBuilder` call arguments for some specific transformation. + */ + static processModifiedArg( + modifiedArg: arkts.AstNode | undefined, + index: number | undefined, + args: readonly arkts.Expression[], + moduleName: string, + name: string | undefined + ): arkts.AstNode | undefined { + if (index === 0 && isForEach(name, moduleName) && !!modifiedArg && arkts.isExpression(modifiedArg)) { + const newFunc = UIFactory.createScriptFunction({ + body: arkts.factory.createBlock([arkts.factory.createReturnStatement(modifiedArg)]), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + returnTypeAnnotation: + factory.getReturnTypeFromArrowParameter(args) ?? factory.getReturnTypeFromTsType(modifiedArg), + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + }); + const returnMemoableInfo = collectMemoableInfoInFunctionReturnType(newFunc); + collectScriptFunctionReturnTypeFromInfo(newFunc, returnMemoableInfo); + return arkts.factory.createArrowFunction(newFunc); + } + return modifiedArg; + } + + /** + * get return type from the second parameter of `ForEach` component. + */ + static getReturnTypeFromArrowParameter(args: readonly arkts.Expression[]): arkts.TypeNode | undefined { + if ( + args.length <= 1 || + !arkts.isArrowFunctionExpression(args[1]) || + args[1].scriptFunction.params.length <= 0 + ) { + return undefined; + } + const argTypeParam: arkts.Expression = args[1].scriptFunction.params[0]; + if (!arkts.isEtsParameterExpression(argTypeParam)) { + return undefined; + } + const type: arkts.AstNode | undefined = argTypeParam.type; + if (type && arkts.isTypeNode(type)) { + return UIFactory.createComplexTypeFromStringAndTypeParameter(TypeNames.ARRAY, [type.clone()]); + } + return undefined; + } + + /** + * get return type from the TsType of value. + */ + static getReturnTypeFromTsType(node: arkts.AstNode): arkts.TypeNode | undefined { + const type = arkts.createTypeNodeFromTsType(node); + if (!type || !arkts.isTypeNode(type)) { + return undefined; + } + return type; + } + /** * add options arguments to set methods in style argument body. */ diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index a80b69b2a91aa58024cf0c7438469fc149a4a7a0..9c4a7531a4476202982d16b8cf0eca804e5583f9 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -18,23 +18,18 @@ import { isAnnotation, matchPrefix } from '../../common/arkts-utils'; import { BuilderLambdaNames, expectNameInTypeReference, isCustomComponentAnnotation } from '../utils'; import { DeclarationCollector } from '../../common/declaration-collector'; import { + ARKUI_FOREACH_SOURCE_NAME, ARKUI_IMPORT_PREFIX_NAMES, - BindableDecl, Dollars, InnerComponentAttributes, + InnerComponentNames, StructDecoratorNames, } from '../../common/predefines'; import { ImportCollector } from '../../common/import-collector'; -import { - collectTypeRecordFromParameter, - collectTypeRecordFromTypeParameterDeclaration, - collectTypeRecordFromTypeParameterInstatiation, - ParameterRecord, - TypeParameterTypeRecord, - TypeRecord, -} from '../../collectors/utils/collect-types'; import { hasMemoAnnotation } from '../../collectors/memo-collectors/utils'; -import { AstNodePointer } from 'common/safe-types'; +import { AstNodePointer } from '../../common/safe-types'; +import { ComponentAttributeCache } from './cache/componentAttributeCache'; +import { MetaDataCollector } from '../../common/metadata-collector'; export type BuilderLambdaDeclInfo = { name: string; @@ -84,6 +79,17 @@ export type OptionsPropertyInfo = { isLinkIntrinsic: boolean; }; +/** + * Determine whether the node is ForEach method declaration or call expression. + * + * @param node method definition node. + * @param sourceName external source name. + */ +export function isForEach(name: string | undefined, sourceName?: string): boolean { + const externalSourceName = sourceName ?? MetaDataCollector.getInstance().externalSourceName; + return name === InnerComponentNames.FOR_EACH && externalSourceName === ARKUI_FOREACH_SOURCE_NAME; +} + export function buildSecondLastArgInfo( type: arkts.Identifier | undefined, isFunctionCall: boolean @@ -428,10 +434,7 @@ export function isBuilderLambdaFunctionCall(nameNode: arkts.Identifier | undefin return false; } const name = nameNode.name; - return ( - name !== BuilderLambdaNames.ORIGIN_METHOD_NAME && - name !== BuilderLambdaNames.TRANSFORM_METHOD_NAME - ); + return name !== BuilderLambdaNames.ORIGIN_METHOD_NAME && name !== BuilderLambdaNames.TRANSFORM_METHOD_NAME; } export function callIsGoodForBuilderLambda(leaf: arkts.CallExpression): boolean { @@ -721,106 +724,3 @@ export function getDeclaredSetAttribtueMethodName(componentName: string): string export function getTransformedComponentName(componentName: string): string { return `${componentName}Impl`; } - -// CACHE -export interface ComponentRecord { - name: string; - attributeRecords: ParameterRecord[]; - typeParams?: TypeParameterTypeRecord[]; - hasRestParameter?: boolean; - hasReceiver?: boolean; - hasLastTrailingLambda?: boolean; -} - -export class ComponentAttributeCache { - private _cache: Map; - private _attributeName: string | undefined; - private _attributeTypeParams: TypeRecord[] | undefined; - private _isCollected: boolean = false; - private static instance: ComponentAttributeCache; - - private constructor() { - this._cache = new Map(); - } - - static getInstance(): ComponentAttributeCache { - if (!this.instance) { - this.instance = new ComponentAttributeCache(); - } - return this.instance; - } - - private collectAttributeName(type: arkts.TypeNode | undefined): string | undefined { - if ( - !type || - !arkts.isETSTypeReference(type) || - !type.part || - !type.part.name || - !arkts.isIdentifier(type.part.name) - ) { - return; - } - this._attributeName = type.part.name.name; - if (type.part.typeParams) { - this._attributeTypeParams = collectTypeRecordFromTypeParameterInstatiation(type.part.typeParams); - } - } - - get attributeName(): string | undefined { - return this._attributeName; - } - - get attributeTypeParams(): TypeRecord[] | undefined { - return this._attributeTypeParams; - } - - reset(): void { - this._cache.clear(); - this._attributeName = undefined; - this._attributeTypeParams = undefined; - this._isCollected = false; - } - - isCollected(): boolean { - return this._isCollected; - } - - collect(node: arkts.MethodDefinition): void { - this.collectAttributeName(node.scriptFunction.returnTypeAnnotation); - if (!this._attributeName) { - return; - } - const name: string = node.name.name; - const hasRestParameter = node.scriptFunction.hasRestParameter; - const hasReceiver = node.scriptFunction.hasReceiver; - const typeParams = collectTypeRecordFromTypeParameterDeclaration(node.scriptFunction.typeParams); - const params = node.scriptFunction.params as arkts.ETSParameterExpression[]; - const attributeRecords: ParameterRecord[] = []; - const hasLastTrailingLambda = checkIsTrailingLambdaInLastParam(params); - params.forEach((p, index) => { - if (index === params.length - 1 && hasLastTrailingLambda) { - return; - } - const record = collectTypeRecordFromParameter(p); - attributeRecords.push(record); - }); - const componentRecord: ComponentRecord = { - name, - attributeRecords, - typeParams, - hasRestParameter, - hasReceiver, - hasLastTrailingLambda, - }; - this._cache.set(name, componentRecord); - this._isCollected = true; - } - - getComponentRecord(name: string): ComponentRecord | undefined { - return this._cache.get(name); - } - - getAllComponentRecords(): ComponentRecord[] { - return Array.from(this._cache.values()); - } -} \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index aaa17782067466fea49acc04fd25a8079a1667cd..6ad6317975430e3b1394666130bf7808f57e28cd 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -19,11 +19,7 @@ import { factory as structFactory } from './struct-translators/factory'; import { factory as builderLambdaFactory } from './builder-lambda-translators/factory'; import { factory as entryFactory } from './entry-translators/factory'; import { AbstractVisitor } from '../common/abstract-visitor'; -import { - ComponentAttributeCache, - isBuilderLambda, - isBuilderLambdaMethodDecl, -} from './builder-lambda-translators/utils'; +import { isBuilderLambda, isBuilderLambdaMethodDecl } from './builder-lambda-translators/utils'; import { isEntryWrapperClass } from './entry-translators/utils'; import { ImportCollector } from '../common/import-collector'; import { DeclarationCollector } from '../common/declaration-collector'; @@ -36,7 +32,6 @@ import { LoaderJson, ResourceInfo, ScopeInfoCollection, - isForEachDecl, } from './struct-translators/utils'; import { collectCustomComponentScopeInfo, @@ -50,6 +45,8 @@ import { InteroperAbilityNames } from './interop/predefines'; import { generateBuilderCompatible } from './interop/builder-interop'; import { builderRewriteByType } from './builder-lambda-translators/builder-factory'; import { MonitorCache } from './property-translators/cache/monitorCache'; +import { ComponentAttributeCache } from './builder-lambda-translators/cache/componentAttributeCache'; +import { MetaDataCollector } from '../common/metadata-collector'; export class CheckedTransformer extends AbstractVisitor { private scope: ScopeInfoCollection; @@ -85,6 +82,13 @@ export class CheckedTransformer extends AbstractVisitor { } } + init(): void { + MetaDataCollector.getInstance() + .setProjectConfig(this.projectConfig) + .setAbsName(this.program?.absName) + .setExternalSourceName(this.externalSourceName); + } + reset(): void { super.reset(); this.scope = { customComponents: [] }; @@ -198,8 +202,6 @@ export class CheckedTransformer extends AbstractVisitor { return structFactory.transformNormalClass(node, this.externalSourceName); } else if (arkts.isCallExpression(node)) { return structFactory.transformCallExpression(node, this.projectConfig, this.resourceInfo); - } else if (arkts.isMethodDefinition(node) && isForEachDecl(node, this.externalSourceName)) { - return structFactory.AddArrowTypeForParameter(node); } else if (arkts.isTSInterfaceDeclaration(node)) { return structFactory.tranformInterfaceMembers(node, this.externalSourceName); } else if ( diff --git a/arkui-plugins/ui-plugins/index.ts b/arkui-plugins/ui-plugins/index.ts index c89dd6eff217958eabd44595a2ff42893c4b9b1d..599b0ad366ac7e4492ef304088fe569105a684b6 100644 --- a/arkui-plugins/ui-plugins/index.ts +++ b/arkui-plugins/ui-plugins/index.ts @@ -20,6 +20,7 @@ import { Plugins, PluginContext, ProjectConfig } from '../common/plugin-context' import { ProgramVisitor } from '../common/program-visitor'; import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../common/predefines'; import { debugLog } from '../common/debug'; +import { MetaDataCollector } from '../common/metadata-collector'; export function uiTransform(): Plugins { return { @@ -134,6 +135,7 @@ function checkedProgramVisit( pluginContext: context, }); program = programVisitor.programVisitor(program); + MetaDataCollector.getInstance().reset(); } return program; } diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 13a120dc40a2bdfb6a5df38951de0d33b4e085bf..a7ebee0c7d42b7c9377d8c09958d755b5ee92911 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -52,7 +52,6 @@ import { ResourceParameter, getResourceParams, isResourceNode, - isForEachCall, getCustomDialogController, isInvalidDialogControllerOptions, findBuilderIndexInControllerOptions, @@ -61,7 +60,7 @@ import { isComputedMethod, } from './utils'; import { collectStateManagementTypeImport, generateThisBacking, hasDecorator } from '../property-translators/utils'; -import { ComponentAttributeCache, isComponentAttributeInterface } from '../builder-lambda-translators/utils'; +import { isComponentAttributeInterface } from '../builder-lambda-translators/utils'; import { ProjectConfig } from '../../common/plugin-context'; import { ImportCollector } from '../../common/import-collector'; import { @@ -76,16 +75,13 @@ import { TypeNames, } from '../../common/predefines'; import { ObservedTranslator } from '../property-translators/index'; -import { - addMemoAnnotation, - collectMemoableInfoInFunctionReturnType, - collectScriptFunctionReturnTypeFromInfo, -} from '../../collectors/memo-collectors/utils'; +import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; import { generateArkUICompatible, isArkUICompatible } from '../interop/interop'; import { GenSymGenerator } from '../../common/gensym-generator'; -import { MethodTranslator } from 'ui-plugins/property-translators/base'; +import { MethodTranslator } from '../property-translators/base'; import { MonitorCache } from '../property-translators/cache/monitorCache'; import { PropertyCache } from '../property-translators/cache/propertyCache'; +import { ComponentAttributeCache } from '../builder-lambda-translators/cache/componentAttributeCache'; export class factory { /** @@ -1086,76 +1082,6 @@ export class factory { ); } - /* - * add arrow function type to arguments of call expression. - */ - static transformCallArguments(node: arkts.CallExpression): arkts.CallExpression { - const newFunc = UIFactory.createScriptFunction({ - body: arkts.factory.createBlock([arkts.factory.createReturnStatement(node.arguments[0])]), - returnTypeAnnotation: this.getReturnTypeWithArrowParameter(node) ?? this.getReturnTypeWithTsType(node), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - }); - const returnMemoableInfo = collectMemoableInfoInFunctionReturnType(newFunc); - collectScriptFunctionReturnTypeFromInfo(newFunc, returnMemoableInfo); - const newArrowArg: arkts.ArrowFunctionExpression = arkts.factory.createArrowFunction(newFunc); - return arkts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ - newArrowArg, - ...node.arguments.slice(1), - ]); - } - - static getReturnTypeWithArrowParameter(node: arkts.CallExpression): arkts.TypeNode | undefined { - const secondArg: arkts.Expression = node.arguments[1]; - if (!arkts.isArrowFunctionExpression(secondArg) || secondArg.scriptFunction.params.length <= 0) { - return undefined; - } - const argTypeParam: arkts.Expression = secondArg.scriptFunction.params[0]; - if (!arkts.isEtsParameterExpression(argTypeParam)) { - return undefined; - } - const type: arkts.AstNode | undefined = argTypeParam.type; - if (type && arkts.isTypeNode(type)) { - return UIFactory.createComplexTypeFromStringAndTypeParameter(TypeNames.ARRAY, [type.clone()]); - } - return undefined; - } - - static getReturnTypeWithTsType(node: arkts.CallExpression): arkts.TypeNode | undefined { - if (node.typeArguments?.length) { - return UIFactory.createComplexTypeFromStringAndTypeParameter(TypeNames.ARRAY, node.typeArguments); - } - const firstArg: arkts.Expression = node.arguments[0]; - const type = arkts.createTypeNodeFromTsType(firstArg); - if (!type || !arkts.isTypeNode(type)) { - return undefined; - } - return type; - } - - static AddArrowTypeForParameter(node: arkts.MethodDefinition): arkts.MethodDefinition { - if (node.scriptFunction.params.length < 2) { - return node; - } - const paramFirst = node.scriptFunction.params[0]; - if (!arkts.isEtsParameterExpression(paramFirst) || !paramFirst.type || !arkts.isTypeNode(paramFirst.type)) { - return node; - } - const script = UIFactory.updateScriptFunction(node.scriptFunction, { - params: [ - arkts.factory.createParameterDeclaration( - arkts.factory.createIdentifier( - paramFirst.identifier.name, - UIFactory.createLambdaFunctionType([], paramFirst.type) - ), - undefined - ), - ...node.scriptFunction.params.slice(1), - ], - }); - return arkts.factory.updateMethodDefinition(node, node.kind, node.name, script, node.modifiers, false); - } - static transformCallExpression( node: arkts.CallExpression, projectConfig: ProjectConfig | undefined, @@ -1164,9 +1090,6 @@ export class factory { if (arkts.isCallExpression(node) && isResourceNode(node)) { return this.transformResource(node, projectConfig, resourceInfo); } - if (arkts.isCallExpression(node) && isForEachCall(node)) { - return this.transformCallArguments(node); - } if (isArkUICompatible(node)) { return generateArkUICompatible(node as arkts.CallExpression); } diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index 1e32a07868894082c9a6d61ab206778c521dba9f..a25c5bf5cb682c69ace9925d3c9e2bb053a27619 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -121,17 +121,6 @@ export function isResourceNode(node: arkts.CallExpression, ignoreDecl: boolean = return true; } -export function isForEachCall(node: arkts.CallExpression): boolean { - if ( - arkts.isIdentifier(node.expression) && - node.expression.name === InnerComponentNames.FOR_EACH && - node.arguments.length >= 2 - ) { - return true; - } - return false; -} - /** * Read the content of file 'loader.json'. * @@ -521,20 +510,6 @@ export function isDynamicName(projectConfig: ProjectConfig): boolean { return uiTransformOptimization ? uiTransformOptimization : isByteCodeHar; } -/** - * Determine whether the node is ForEach method declaration. - * - * @param node method definition node. - * @param sourceName external source name. - */ -export function isForEachDecl(node: arkts.MethodDefinition, sourceName: string | undefined): boolean { - const isForEach: boolean = !!node.name && node.name.name === InnerComponentNames.FOR_EACH; - const isMethodDecl: boolean = - !!node.scriptFunction && - arkts.hasModifierFlag(node.scriptFunction, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); - return isForEach && isMethodDecl && !!sourceName && sourceName === ARKUI_FOREACH_SOURCE_NAME; -} - export function getCustomDialogController(node: arkts.ClassProperty): string { const key = node.key; let controllerName: string = '';