From 23f75fdd621a15ccfa9b8dbf429cc959093b6cda Mon Sep 17 00:00:00 2001 From: Cuecuexiaoyu Date: Tue, 22 Jul 2025 11:35:03 +0800 Subject: [PATCH 1/2] CustomDialog fix Signed-off-by: Cuecuexiaoyu Change-Id: I5ac20cf7b9768afe95bede7ae1e9241ea903276a --- .../custom-dialog/base-custom-dialog.ets | 9 +++++- .../ui-plugins/property-translators/prop.ts | 4 +-- .../property-translators/regularProperty.ts | 31 +++++++++++++++++-- .../ui-plugins/property-translators/utils.ts | 22 ++++++++++++- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/arkui-plugins/test/demo/mock/decorators/custom-dialog/base-custom-dialog.ets b/arkui-plugins/test/demo/mock/decorators/custom-dialog/base-custom-dialog.ets index 82334f263..e527defd1 100644 --- a/arkui-plugins/test/demo/mock/decorators/custom-dialog/base-custom-dialog.ets +++ b/arkui-plugins/test/demo/mock/decorators/custom-dialog/base-custom-dialog.ets @@ -15,7 +15,14 @@ import { Text, Column, Component, Entry, Button, ClickEvent } from "@ohos.arkui.component" import { State, Link, Prop } from "@ohos.arkui.stateManagement" -import { CustomDialog, CustomDialogController, DismissDialogAction, DismissReason, DialogAlignment, CustomDialogControllerOptions } from "@kit.ArkUI" +import { + CustomDialog, + CustomDialogController, + DismissDialogAction, + DismissReason, + DialogAlignment, + CustomDialogControllerOptions +} from "@ohos.arkui.component" import hilog from '@ohos.hilog' @CustomDialog diff --git a/arkui-plugins/ui-plugins/property-translators/prop.ts b/arkui-plugins/ui-plugins/property-translators/prop.ts index df2bce793..efabedecd 100644 --- a/arkui-plugins/ui-plugins/property-translators/prop.ts +++ b/arkui-plugins/ui-plugins/property-translators/prop.ts @@ -19,12 +19,12 @@ import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { CustomComponentNames } from '../utils'; import { - generateToRecord, + collectStateManagementTypeImport, createGetter, createSetter2, generateGetOrSetCall, generateThisBacking, - collectStateManagementTypeImport, + generateToRecord, hasDecorator, PropertyCache, } from './utils'; diff --git a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index f5d4a4724..03ff22e98 100644 --- a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -15,11 +15,19 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, generateToRecord, generateThisBacking, createSetter2, PropertyCache } from './utils'; +import { + createGetter, + generateToRecord, + generateThisBacking, + createSetter2, + PropertyCache, + isCustomDialogController, +} from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; +import { CustomComponentNames } from '../utils'; export class RegularPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { @@ -31,7 +39,14 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini cacheTranslatedInitializer(newName: string, originalName: string): void { const value = this.property.value ?? arkts.factory.createUndefinedLiteral(); - const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName, value); + let initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName, value); + if ( + !!this.property.typeAnnotation && + !!this.structInfo.annotations.customdialog && + isCustomDialogController(this.property.typeAnnotation) + ) { + initializeStruct = this.generateControllerInit(originalName, initializeStruct); + } PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); @@ -87,7 +102,7 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini generateInitializeStruct(newName: string, originalName: string, value: arkts.Expression): arkts.AstNode { const binaryItem = arkts.factory.createBinaryExpression( factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier('initializers'), + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), originalName ), value ?? arkts.factory.createUndefinedLiteral(), @@ -100,6 +115,16 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini ); return arkts.factory.createExpressionStatement(assign); } + + generateControllerInit(originalName: string, initializeStruct: arkts.AstNode): arkts.AstNode { + return arkts.factory.createIfStatement( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + originalName + ), + arkts.factory.createBlock([initializeStruct]) + ); + } } export class RegularInterfaceTranslator extends InterfacePropertyTranslator { diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 0c2ae71c6..13172f7e6 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -29,6 +29,7 @@ import { findCanAddMemoFromParameter, findCanAddMemoFromTypeAnnotation, } from '../../collectors/memo-collectors/utils'; +import { CustomDialogNames } from '../utils'; export interface DecoratorInfo { annotation: arkts.AnnotationUsage; @@ -317,7 +318,11 @@ export function getValueInProvideAnnotation(node: arkts.ClassProperty): ProvideO return undefined; } -function getValueInObjectAnnotation(anno: arkts.AnnotationUsage, decoratorName: DecoratorNames, key: string): string | boolean | undefined { +function getValueInObjectAnnotation( + anno: arkts.AnnotationUsage, + decoratorName: DecoratorNames, + key: string +): string | boolean | undefined { const isSuitableAnnotation: boolean = !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName; if (!isSuitableAnnotation) { @@ -382,6 +387,21 @@ export function generateToRecord(newName: string, originalName: string): arkts.P ); } +export function isCustomDialogController(type: arkts.TypeNode): boolean { + if (arkts.isETSUnionType(type)) { + return !!type.types.find((item: arkts.TypeNode) => { + return isCustomDialogController(item) + }) + } + return ( + !!arkts.isETSTypeReference(type) && + !!type.part && + !!type.part.name && + arkts.isIdentifier(type.part.name) && + type.part.name.name === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER + ); +} + export function removeImplementProperty(originalName: string): string { const prefix = ObservedNames.PROPERTY_PREFIX; return originalName.substring(prefix.length); -- Gitee From 43e9288defc5759e4c3537b7414ac9f525b66c6b Mon Sep 17 00:00:00 2001 From: Cuecuexiaoyu Date: Tue, 22 Jul 2025 10:23:09 +0800 Subject: [PATCH 2/2] modify bindable array type Signed-off-by: Cuecuexiaoyu Change-Id: I327444ebef654f76fdeb468f7007929a05464f88 --- .../double-dollar/double-dollar-toggle.ets | 37 ++++ .../animation/animatable-extend-basic.test.ts | 2 +- .../animation/animation-basic.test.ts | 2 +- .../custom-dialog/base-custom-dialog.test.ts | 29 ++-- .../custom-dialog/controller-in-build.test.ts | 23 +-- .../extends-dialog-controller.test.ts | 11 +- .../double-dollar-toggle.test.ts | 164 ++++++++++++++++++ .../builder-lambda-translators/factory.ts | 16 +- .../builder-lambda-translators/utils.ts | 36 +--- .../ui-plugins/property-translators/utils.ts | 4 +- 10 files changed, 252 insertions(+), 72 deletions(-) create mode 100644 arkui-plugins/test/demo/mock/double-dollar/double-dollar-toggle.ets create mode 100644 arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts diff --git a/arkui-plugins/test/demo/mock/double-dollar/double-dollar-toggle.ets b/arkui-plugins/test/demo/mock/double-dollar/double-dollar-toggle.ets new file mode 100644 index 000000000..20ff29b73 --- /dev/null +++ b/arkui-plugins/test/demo/mock/double-dollar/double-dollar-toggle.ets @@ -0,0 +1,37 @@ +/* + * 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 { Text, Column, Component, $$, Toggle, ToggleType } from "@ohos.arkui.component" +import { State } from "@ohos.arkui.stateManagement" + +let c: boolean[] = [true, false, true]; + +class BooleanClass { + isOn: boolean = true; +} + +@Component +struct MyStateSample { + @State boo: boolean[] = [true, false, true]; + @State booClass: BooleanClass = new BooleanClass(); + + build() { + Column() { + Toggle({ type: ToggleType.Checkbox, isOn: $$(this.boo[0]) }) + Toggle({ type: ToggleType.Checkbox, isOn: $$(this.booClass.isOn) }) + Toggle({ type: ToggleType.Checkbox, isOn: $$(c[1]) }) + } + } +} \ No newline at end of file diff --git a/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts index fa3db797a..e1ab7ae03 100644 --- a/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts @@ -73,7 +73,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ public __updateStruct(initializers: (__Options_AnimatablePropertyExample | undefined)): void {} @memo() public build() { - Column(undefined, undefined, (() => { + Column(undefined, undefined, @memo() (() => { Text(@memo() ((instance: TextAttribute): void => { instance.animationStart({ duration: 2000, diff --git a/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts index f65042c92..9eeeb0fd7 100644 --- a/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts @@ -72,7 +72,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ public __updateStruct(initializers: (__Options_AnimatablePropertyExample | undefined)): void {} @memo() public build() { - Column(undefined, undefined, (() => { + Column(undefined, undefined, @memo() (() => { Text(@memo() ((instance: TextAttribute): void => { instance.animationStart({ duration: 2000, diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts index 9b72b4d35..6de9a9682 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts @@ -56,7 +56,7 @@ import { Text as Text, Column as Column, Component as Component, Entry as Entry, import { State as State, Link as Link, Prop as Prop } from "@ohos.arkui.stateManagement"; -import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, DismissDialogAction as DismissDialogAction, DismissReason as DismissReason, DialogAlignment as DialogAlignment, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@kit.ArkUI"; +import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, DismissDialogAction as DismissDialogAction, DismissReason as DismissReason, DialogAlignment as DialogAlignment, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@ohos.arkui.component"; import hilog from "@ohos.hilog"; @@ -64,16 +64,19 @@ function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_aaController = ((({let gensym___180078470 = initializers; - (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); - this.__backing_text = STATE_MGMT_FACTORY.makeState(this, "text", ((({let gensym___135728974 = initializers; - (((gensym___135728974) == (null)) ? undefined : gensym___135728974.text)})) ?? ("text"))); - this.__backing_cancel = ((({let gensym___54390975 = initializers; - (((gensym___54390975) == (null)) ? undefined : gensym___54390975.cancel)})) ?? ((() => {}))); - this.__backing_confirm = ((({let gensym___265534970 = initializers; - (((gensym___265534970) == (null)) ? undefined : gensym___265534970.confirm)})) ?? ((() => {}))); - this.__backing_hh = STATE_MGMT_FACTORY.makeState(this, "hh", ((({let gensym___261031583 = initializers; - (((gensym___261031583) == (null)) ? undefined : gensym___261031583.hh)})) ?? ("nihao"))); + if (({let gensym___45519047 = initializers; + (((gensym___45519047) == (null)) ? undefined : gensym___45519047.aaController)})) { + this.__backing_aaController = ((({let gensym___180078470 = initializers; + (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); + } + this.__backing_text = STATE_MGMT_FACTORY.makeState(this, "text", ((({let gensym___217676902 = initializers; + (((gensym___217676902) == (null)) ? undefined : gensym___217676902.text)})) ?? ("text"))); + this.__backing_cancel = ((({let gensym___25471281 = initializers; + (((gensym___25471281) == (null)) ? undefined : gensym___25471281.cancel)})) ?? ((() => {}))); + this.__backing_confirm = ((({let gensym___213253394 = initializers; + (((gensym___213253394) == (null)) ? undefined : gensym___213253394.confirm)})) ?? ((() => {}))); + this.__backing_hh = STATE_MGMT_FACTORY.makeState(this, "hh", ((({let gensym___210200872 = initializers; + (((gensym___210200872) == (null)) ? undefined : gensym___210200872.hh)})) ?? ("nihao"))); } public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} @@ -155,8 +158,8 @@ function main() {} @Component() final struct CustomDialogUser extends CustomComponent { public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_dialogController = ((({let gensym___95501822 = initializers; - (((gensym___95501822) == (null)) ? undefined : gensym___95501822.dialogController)})) ?? (new CustomDialogController({ + this.__backing_dialogController = ((({let gensym___56650533 = initializers; + (((gensym___56650533) == (null)) ? undefined : gensym___56650533.dialogController)})) ?? (new CustomDialogController({ builder: @memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts index 04d08c3ea..53e1ee0aa 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts @@ -64,12 +64,15 @@ function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_aaController = ((({let gensym___180078470 = initializers; - (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); - this.__backing_text = STATE_MGMT_FACTORY.makeState(this, "text", ((({let gensym___135728974 = initializers; - (((gensym___135728974) == (null)) ? undefined : gensym___135728974.text)})) ?? ("text"))); - this.__backing_hh = STATE_MGMT_FACTORY.makeState(this, "hh", ((({let gensym___200130389 = initializers; - (((gensym___200130389) == (null)) ? undefined : gensym___200130389.hh)})) ?? ("nihao"))); + if (({let gensym___45519047 = initializers; + (((gensym___45519047) == (null)) ? undefined : gensym___45519047.aaController)})) { + this.__backing_aaController = ((({let gensym___180078470 = initializers; + (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); + } + this.__backing_text = STATE_MGMT_FACTORY.makeState(this, "text", ((({let gensym___217676902 = initializers; + (((gensym___217676902) == (null)) ? undefined : gensym___217676902.text)})) ?? ("text"))); + this.__backing_hh = STATE_MGMT_FACTORY.makeState(this, "hh", ((({let gensym___112288773 = initializers; + (((gensym___112288773) == (null)) ? undefined : gensym___112288773.hh)})) ?? ("nihao"))); } public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} @@ -127,18 +130,18 @@ function main() {} Column(undefined, undefined, @memo() (() => { Button(@memo() ((instance: ButtonAttribute): void => { instance.onClick(((e: ClickEvent) => { - let dialogController: (CustomDialogController | undefined) = ({let gensym___176924847: (CustomDialogController | undefined); - gensym___176924847 = new CustomDialogController({ + let dialogController: (CustomDialogController | undefined) = ({let gensym___220374545: (CustomDialogController | undefined); + gensym___220374545 = new CustomDialogController({ builder: @memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); - instance.__setDialogController__((gensym___176924847 as CustomDialogController)); + instance.__setDialogController__((gensym___220374545 as CustomDialogController)); return instance; }), {}, undefined); }), baseComponent: this, }) - gensym___176924847}); + gensym___220374545}); })).backgroundColor(0x317aff); return; }), "click me", undefined, undefined); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts index c2e072132..955038153 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts @@ -54,8 +54,11 @@ function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_aaController = ((({let gensym___180078470 = initializers; - (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); + if (({let gensym___45519047 = initializers; + (((gensym___45519047) == (null)) ? undefined : gensym___45519047.aaController)})) { + this.__backing_aaController = ((({let gensym___180078470 = initializers; + (((gensym___180078470) == (null)) ? undefined : gensym___180078470.aaController)})) ?? (undefined)); + } } public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} @@ -104,8 +107,8 @@ class DialogControllerV3 extends DialogControllerV2 { @Component() final struct CustomDialogUser extends CustomComponent { public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { - this.__backing_dialogController = ((({let gensym___51459619 = initializers; - (((gensym___51459619) == (null)) ? undefined : gensym___51459619.dialogController)})) ?? ((new CustomDialogController(({ + this.__backing_dialogController = ((({let gensym___176924847 = initializers; + (((gensym___176924847) == (null)) ? undefined : gensym___176924847.dialogController)})) ?? ((new CustomDialogController(({ gridCount: 4, showInSubWindow: true, builder: @memo() (() => { diff --git a/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts new file mode 100644 index 000000000..8387fe7ae --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts @@ -0,0 +1,164 @@ +/* + * 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 path from 'path'; +import { PluginTester } from '../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; +import { parseDumpSrc } from '../../../utils/parse-string'; +import { uiNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; +import { uiTransform } from '../../../../ui-plugins'; +import { Plugins } from '../../../../common/plugin-context'; + +const DOUBLE_DOLLAR_DIR_PATH: string = 'double-dollar'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, DOUBLE_DOLLAR_DIR_PATH, 'double-dollar-toggle.ets'), +]; + +const pluginTester = new PluginTester('test toggle bindable capability', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { Bindable as Bindable } from "arkui.component.common"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, $$ as $$, Toggle as Toggle, ToggleType as ToggleType } from "@ohos.arkui.component"; + +import { State as State } from "@ohos.arkui.stateManagement"; + +let c: Array; + +function main() {} + +c = [true, false, true]; + +class BooleanClass { + public isOn: boolean = true; + + public constructor() {} + +} + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_boo = STATE_MGMT_FACTORY.makeState>(this, "boo", ((({let gensym___9142460 = initializers; + (((gensym___9142460) == (null)) ? undefined : gensym___9142460.boo)})) ?? ([true, false, true]))); + this.__backing_booClass = STATE_MGMT_FACTORY.makeState(this, "booClass", ((({let gensym___145381365 = initializers; + (((gensym___145381365) == (null)) ? undefined : gensym___145381365.booClass)})) ?? (new BooleanClass()))); + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_boo?: IStateDecoratedVariable>; + + public get boo(): Array { + return this.__backing_boo!.get(); + } + + public set boo(value: Array) { + this.__backing_boo!.set(value); + } + + private __backing_booClass?: IStateDecoratedVariable; + + public get booClass(): BooleanClass { + return this.__backing_booClass!.get(); + } + + public set booClass(value: BooleanClass) { + this.__backing_booClass!.set(value); + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Toggle(undefined, { + type: ToggleType.Checkbox, + isOn: ({ + value: this.boo[0], + onChange: ((value: boolean) => { + this.boo[0] = value; + }), + } as Bindable), + }, undefined); + Toggle(undefined, { + type: ToggleType.Checkbox, + isOn: ({ + value: this.booClass.isOn, + onChange: ((value: boolean) => { + this.booClass.isOn = value; + }), + } as Bindable), + }, undefined); + Toggle(undefined, { + type: ToggleType.Checkbox, + isOn: ({ + value: c[1], + onChange: ((value: boolean) => { + c[1] = value; + }), + } as Bindable), + }, undefined); + })); + } + + private constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + set boo(boo: (Array | undefined)) + + get boo(): (Array | undefined) + set __backing_boo(__backing_boo: (IStateDecoratedVariable> | undefined)) + + get __backing_boo(): (IStateDecoratedVariable> | undefined) + set booClass(booClass: (BooleanClass | undefined)) + + get booClass(): (BooleanClass | undefined) + set __backing_booClass(__backing_booClass: (IStateDecoratedVariable | undefined)) + + get __backing_booClass(): (IStateDecoratedVariable | undefined) + +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test toggle bindable capability', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index 17af3f52a..c3a8f31af 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -35,8 +35,6 @@ import { isBuilderLambdaFunctionCall, isSafeType, replaceBuilderLambdaDeclMethodName, - getDecalTypeFromValue, - hasBindableProperty, isDoubleDollarCall, InstanceCallInfo, isStyleChainedCall, @@ -48,6 +46,7 @@ import { checkIsWithInIfConditionScope, BuilderLambdaConditionBranchInfo, BuilderLambdaChainingCallArgInfo, + getArgumentType, } from './utils'; import { hasDecorator, isDecoratorIntrinsicAnnotation } from '../property-translators/utils'; import { factory as PropertyFactory } from '../property-translators/factory'; @@ -122,14 +121,11 @@ export class factory { params, (arg, param, index) => { const _param = param as arkts.ETSParameterExpression; - let hasBindable: boolean = false; let isDoubleDollar: boolean = false; if (index === 0 && !!arg) { - const type = _param.type?.clone(); - hasBindable = !!type && hasBindableProperty(type, BindableDecl.BINDABLE); isDoubleDollar = isDoubleDollarCall(arg); } - if (hasBindable && isDoubleDollar && !!arg) { + if (isDoubleDollar && !!arg) { const bindableArg: arkts.Expression = (arg as arkts.CallExpression).arguments[0]; argInfo.push({ arg: factory.updateBindableStyleArguments(bindableArg) }); } else if (!!arg) { @@ -145,7 +141,7 @@ export class factory { * transform bundable arguments in style node, e.g. `Radio().checked($$(this.checked))` => `Radio().checked({value: xxx, onChange: xxx})`. */ static updateBindableStyleArguments(bindableArg: arkts.Expression): arkts.Expression { - const valueType: arkts.TypeNode = getDecalTypeFromValue(bindableArg); + const valueType: arkts.TypeNode = getArgumentType(bindableArg); const objExp: arkts.ObjectExpression = arkts.factory.createObjectExpression( arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, [factory.generateValueProperty(bindableArg), factory.generateOnChangeArrowFunc(bindableArg, valueType)], @@ -334,8 +330,6 @@ export class factory { if (!prop.key || !prop.value || !(decl = arkts.getDecl(prop.key)) || !arkts.isMethodDefinition(decl)) { return prop; } - const returnType: arkts.TypeNode | undefined = decl.scriptFunction.returnTypeAnnotation; - const isBindable: boolean = !!returnType && hasBindableProperty(returnType, BindableDecl.BINDABLE); let isBuilderParam: boolean = false; let isLinkIntrinsic: boolean = false; decl.scriptFunction.annotations.forEach((anno) => { @@ -343,7 +337,7 @@ export class factory { isLinkIntrinsic ||= isDecoratorIntrinsicAnnotation(anno, DecoratorIntrinsicNames.LINK); }); - if (isBindable && isDoubleDollarCall(prop.value)) { + if (isDoubleDollarCall(prop.value)) { return factory.updateBindableProperty(prop); } else if (isBuilderParam && arkts.isArrowFunctionExpression(prop.value)) { addMemoAnnotation(prop.value); @@ -719,7 +713,7 @@ export class factory { prop.value.arguments.length === 1 ) { let bindableArg = prop.value.arguments[0]; - valueType = getDecalTypeFromValue(bindableArg); + valueType = getArgumentType(bindableArg); res.push( factory.generateValueProperty(bindableArg), factory.generateOnChangeArrowFunc(bindableArg, valueType) diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index 711dcfb4a..261e786c2 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -430,31 +430,6 @@ export function builderLambdaFunctionName(node: arkts.CallExpression): string | return undefined; } -/** - * Determine whether the node `` is `` bindable property. - * - * @param type type node - * @param bindableDecl bindable decalaration name - */ -export function hasBindableProperty(type: arkts.AstNode, bindableDecl: BindableDecl): boolean { - let res: boolean = false; - if (arkts.isETSUnionType(type)) { - type.types.forEach((item: arkts.TypeNode) => { - res = res || hasBindableProperty(item, bindableDecl); - }); - } - if (arkts.isETSTypeReference(type)) { - res = - res || - (!!type.part && - !!type.part.name && - arkts.isIdentifier(type.part.name) && - type.part.name.name === bindableDecl); - } - - return res; -} - /** * Determine whether `` is `$$()` call expression node. * @@ -487,16 +462,17 @@ export function isDoubleDollarCall( } /** - * get declaration type from `{xxx: }` or `fun()`. + * get declaration type from function call argument `fun()`. * - * @param value type node + * @param arg first argument in call expression. */ -export function getDecalTypeFromValue(value: arkts.Expression): arkts.TypeNode { - const decl: arkts.AstNode | undefined = arkts.getDecl(value); +export function getArgumentType(arg: arkts.Expression): arkts.TypeNode { + const isArrayElement = arkts.isMemberExpression(arg) && !!arg.property && arkts.isNumberLiteral(arg.property); + const decl: arkts.AstNode | undefined = arkts.getDecl(arg); if (!decl || !arkts.isClassProperty(decl)) { throw new Error('cannot get declaration'); } - if (isArrayType(decl.typeAnnotation!)) { + if (isArrayElement) { return getElementTypeFromArray(decl.typeAnnotation!)!; } return decl.typeAnnotation!; diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 13172f7e6..8c3a3d35f 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -390,8 +390,8 @@ export function generateToRecord(newName: string, originalName: string): arkts.P export function isCustomDialogController(type: arkts.TypeNode): boolean { if (arkts.isETSUnionType(type)) { return !!type.types.find((item: arkts.TypeNode) => { - return isCustomDialogController(item) - }) + return isCustomDialogController(item); + }); } return ( !!arkts.isETSTypeReference(type) && -- Gitee