diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index 87bdd941348238e34a500f4bb95d6523babd0a68..6101ba6ba069db34d6b53dd255254f66717e51ad 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -37,6 +37,7 @@ export const ARKUI_IMPORT_PREFIX_NAMES: (string | RegExp)[] = [/arkui\..*/, /@oh export const MEMO_IMPORT_SOURCE_NAME: string = 'arkui.stateManagement.runtime'; export const CUSTOM_COMPONENT_IMPORT_SOURCE_NAME: string = 'arkui.component.customComponent'; +export const CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME: string = 'arkui.component.customDialogController'; export const ENTRY_POINT_IMPORT_SOURCE_NAME: string = 'arkui.UserView'; export const ARKUI_COMPONENT_COMMON_SOURCE_NAME: string = 'arkui.component.common'; export const ARKUI_FOREACH_SOURCE_NAME: string = 'arkui.component.forEach'; @@ -123,7 +124,11 @@ export enum DecoratorNames { TRACK = 'Track', JSONSTRINGIFYIGNORE = 'JSONStringifyIgnore', JSONRENAME = 'JSONRename', - ANIMATABLE_EXTEND = 'AnimatableExtend' + ANIMATABLE_EXTEND = 'AnimatableExtend', + PROP_REF = 'PropRef', + LOCAL = 'Local', + LOCAL_STORAGE_PROP_REF = 'LocalStoragePropRef', + STORAGE_PROP_REF = 'StoragePropRef', } export enum DecoratorIntrinsicNames { @@ -143,6 +148,9 @@ export enum StateManagementTypes { PROVIDE_DECORATED = 'IProvideDecoratedVariable', CONSUME_DECORATED = 'IConsumeDecoratedVariable', OBJECT_LINK_DECORATED = 'IObjectLinkDecoratedVariable', + PROP_REF_DECORATED = 'IPropRefDecoratedVariable', + LOCAL_DECORATED = 'ILocalDecoratedVariable', + LOCAL_STORAGE_PROP_REF_DECORATED = 'ILocalStoragePropRefDecoratedVariable', MUTABLE_STATE_META = 'IMutableStateMeta', OBSERVED_OBJECT = 'IObservedObject', WATCH_ID_TYPE = 'WatchIdType', @@ -157,7 +165,10 @@ export enum StateManagementTypes { MAKE_STATE = 'makeState', MAKE_LINK = 'makeLink', MAKE_PROP = 'makeProp', + MAKE_PROP_REF = 'makePropRef', + MAKE_LOCAL = 'makeLocal', MAKE_STORAGE_PROP_REF = 'makeStoragePropRef', + MAKE_LOCAL_STORAGE_PROP_REF = 'makeLocalStoragePropRef', MAKE_STORAGE_LINK = 'makeStorageLink', MAKE_LOCAL_STORAGE_LINK = 'makeLocalStorageLink', MAKE_PROVIDE = 'makeProvide', @@ -203,13 +214,17 @@ export const DECORATOR_TYPE_MAP = new Map( [DecoratorNames.STATE, StateManagementTypes.STATE_DECORATED], [DecoratorNames.LINK, StateManagementTypes.LINK_SOURCE_TYPE], [DecoratorNames.PROP, StateManagementTypes.PROP_DECORATED], + [DecoratorNames.PROP_REF, StateManagementTypes.PROP_REF_DECORATED], [DecoratorNames.STORAGE_LINK, StateManagementTypes.STORAGE_LINK_DECORATED], [DecoratorNames.STORAGE_PROP, StateManagementTypes.STORAGE_PROP_REF_DECORATED], + [DecoratorNames.STORAGE_PROP_REF, StateManagementTypes.STORAGE_PROP_REF_DECORATED], + [DecoratorNames.LOCAL_STORAGE_PROP_REF, StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED], [DecoratorNames.LOCAL_STORAGE_PROP, StateManagementTypes.SYNCED_PROPERTY], [DecoratorNames.LOCAL_STORAGE_LINK, StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED], [DecoratorNames.OBJECT_LINK, StateManagementTypes.OBJECT_LINK_DECORATED], [DecoratorNames.PROVIDE, StateManagementTypes.PROVIDE_DECORATED], [DecoratorNames.CONSUME, StateManagementTypes.CONSUME_DECORATED], + [DecoratorNames.LOCAL, StateManagementTypes.LOCAL_DECORATED], ]); export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map([ @@ -219,12 +234,16 @@ export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map void = () => { + } + confirm: () => void = () => { + } + @State hh: string = 'nihao' + build() { + Column() { + Text('CustomDialog One') + .fontSize(30) + .height(100) + Button('Close') + .onClick((e: ClickEvent) => { + if (this.aaController != undefined) { + this.aaController!.close(); + } + }) + .margin(20) + } + } +} + +@Component +struct CustomDialogUser { + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomDialogExample({ + cancel: ()=> { this.onCancel(); }, + confirm: ()=> { this.onAccept(); } + }), + cancel: this.existApp, + autoCancel: true, + alignment: DialogAlignment.Center, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + showInSubWindow: true, + isModal: true, + customStyle: false, + cornerRadius: 10, + focusable: true + }) + + aboutToDisappear() { + this.dialogController = null; + } + + onCancel() { + console.info('Callback when the first button is clicked'); + } + + onAccept() { + console.info('Callback when the second button is clicked'); + } + + existApp() { + console.info('Click the callback in the blank area'); + } + + build() { + Column() { + Button('click me') + .onClick((e: ClickEvent) => { + if (this.dialogController != null) { + this.dialogController!.open(); + } + }).backgroundColor(0x317aff) + } + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/custom-dialog/builder-dialog-options.ets b/arkui-plugins/test/demo/mock/decorators/custom-dialog/builder-dialog-options.ets new file mode 100644 index 0000000000000000000000000000000000000000..e041a012ed72630c43d5f60951e0b4ed8162671b --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/custom-dialog/builder-dialog-options.ets @@ -0,0 +1,44 @@ +/* + * 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, Builder } from "@ohos.arkui.component" +import { CustomDialog, CustomDialogController, CustomDialogControllerOptions } from "@kit.ArkUI" +import hilog from '@ohos.hilog' + +@Builder function builder1(str: string) {} + +@Builder function builder2() {} + +@Component +struct CustomDialogUser { + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: () => { builder1('nihao') }, + }) + + build() { + Column() {} + } +} + +@Component +struct CustomDialogUser2 { + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: builder2, + }) + + build() { + Column() {} + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/custom-dialog/controller-in-build.ets b/arkui-plugins/test/demo/mock/decorators/custom-dialog/controller-in-build.ets new file mode 100644 index 0000000000000000000000000000000000000000..c87bc2e13d0018ae043a0da87d0c09b977ab2dba --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/custom-dialog/controller-in-build.ets @@ -0,0 +1,46 @@ +/* + * 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, Button, ClickEvent } from "@ohos.arkui.component" +import { State, Link, Prop } from "@ohos.arkui.stateManagement" +import { CustomDialog, CustomDialogController, CustomDialogControllerOptions } from "@kit.ArkUI" +import hilog from '@ohos.hilog' + +@CustomDialog +struct CustomDialogExample { + aaController?: CustomDialogController; + @State text: string = 'text'; + @State hh: string = 'nihao' + build() { + Column() { + Text('CustomDialog One') + } + } +} + +@Component +struct CustomDialogUser { + + build() { + Column() { + Button('click me') + .onClick((e: ClickEvent) => { + let dialogController: CustomDialogController | undefined = new CustomDialogController({ + builder: CustomDialogExample({}) + }) + }).backgroundColor(0x317aff) + } + } +} diff --git a/arkui-plugins/test/demo/mock/decorators/custom-dialog/extends-dialog-controller.ets b/arkui-plugins/test/demo/mock/decorators/custom-dialog/extends-dialog-controller.ets new file mode 100644 index 0000000000000000000000000000000000000000..3829a2b74c8bb16add03dc09b2ddc66809dfa9b6 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/custom-dialog/extends-dialog-controller.ets @@ -0,0 +1,64 @@ +/* + * 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, Entry, Button, ClickEvent } from "@ohos.arkui.component" +import { CustomDialog, CustomDialogController, CustomDialogControllerOptions } from "@kit.ArkUI" + +@CustomDialog +struct CustomDialogExample { + aaController?: CustomDialogController; + + build() { + Column() {} + } +} + +class DialogControllerV2 extends CustomDialogController { + options: CustomDialogControllerOptions; + + constructor(options: CustomDialogControllerOptions) { + super(options); + this.options = options; + } +} + +class DialogControllerV3 extends DialogControllerV2 { + options: CustomDialogControllerOptions; + + constructor(options: CustomDialogControllerOptions) { + super(options); + this.options = options; + } +} + +@Component +struct CustomDialogUser { + dialogController: CustomDialogController | null = new CustomDialogController({ + gridCount: 4, + showInSubWindow: true, + builder: CustomDialogExample(), + } as CustomDialogControllerOptions) as DialogControllerV3 + + build() { + Column() { + Button('click me') + .onClick((e: ClickEvent) => { + if (this.dialogController != null) { + this.dialogController!.open(); + } + }) + } + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.ets b/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..72cc3f9c772a57ad4d743dd8a2a1a96116257569 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.ets @@ -0,0 +1,41 @@ +/* + * 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 { Component } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins +import { LocalStoragePropRef } from "@ohos.arkui.stateManagement" + +class Person{ + name: string = '' + constructor(name: string){} +} + +enum Status { + Success = 200, + NotFound = 404, + ServerError = 500 +} + +@Component +struct MyStateSample { + @LocalStoragePropRef('Prop1') arrayB: number[] = [1,2,3]; + @LocalStoragePropRef('Prop2') objectB: Object = {}; + @LocalStoragePropRef('Prop3') dateB: Date = new Date('2021-09-09'); + @LocalStoragePropRef('Prop4') setB: Set = new Set(); + @LocalStoragePropRef('Prop5') mapB: Map = new Map(); + @LocalStoragePropRef('Prop7') classB: Person = new Person("Kevin"); + @LocalStoragePropRef('Prop8') enumB: Status = Status.NotFound; + + build() {} +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.ets b/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..dce193d2fc340f85be92d3f789e7feb2c4d61649 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.ets @@ -0,0 +1,28 @@ +/* + * 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 { Component } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins +import { LocalStoragePropRef } from "@ohos.arkui.stateManagement" + +@Component +struct MyStateSample { + @LocalStoragePropRef('Prop1') numB: number = 43; + @LocalStoragePropRef('Prop2') stringB: string = 'BB'; + @LocalStoragePropRef('Prop3') booleanB: boolean = false; + @LocalStoragePropRef('Prop4') undefinedB: undefined = undefined; + @LocalStoragePropRef('Prop5') nullB: null = null; + + build() {} +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-basic-type.ets b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-basic-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..917703d1e7d0ecdefaf85813871e1298d26371ed --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-basic-type.ets @@ -0,0 +1,29 @@ +/* + * 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 { Component } from "@ohos.arkui.component" +import { PropRef } from "@ohos.arkui.stateManagement" + +@Component +struct PropParent { + @PropRef propVar1: string = 'propVar1'; + @PropRef propVar2: number = 50; + @PropRef propVar3: boolean = true; + @PropRef propVar4: undefined = undefined; + @PropRef propVar5: null = null; + + build() { + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-complex-type.ets b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-complex-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..419b95b45b23067cc1aa5970a72c092697e3f076 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-complex-type.ets @@ -0,0 +1,49 @@ +/* + * 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 { Component } from "@ohos.arkui.component" +import { PropRef } from "@ohos.arkui.stateManagement" + +class Per { + num: number; + constructor(num: number) { + this.num = num; + } +} + +enum PropType { + TYPE1 = 0, + TYPE2 = 1, + TYPE3 = 3 +} + +@Component +struct Parent { + @PropRef propVar1: Per = new Per(6); + @PropRef propVar2: Array = new Array(3,6,8); + @PropRef propVar3: PropType = PropType.TYPE3; + @PropRef propVar4: Set = new Set(new Array('aa', 'bb')); + @PropRef propVar5: boolean[] = [true, false]; + @PropRef propVar6: Array = new Array(new Per(7), new Per(11)); + @PropRef propVar7: Per[] = [new Per(7), new Per(11)]; + @PropRef propVar8: (sr: string)=>void = (sr: string)=>{}; + @PropRef propVar9: Date = new Date('2025-4-23'); + @PropRef propVar10: Map = new Map([[0, new Per(7)], [1, new Per(10)]]); + @PropRef propVar11: string | number = 0.0; + @PropRef propVar12: Set | Per = new Per(6); + + build() { + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-without-initialization.ets b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-without-initialization.ets new file mode 100644 index 0000000000000000000000000000000000000000..66002c9f04c95d8384f13b75c15c67d773beb534 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/prop-ref/prop-ref-without-initialization.ets @@ -0,0 +1,30 @@ +/* + * 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 { Component } from "@ohos.arkui.component" +import { PropRef } from "@ohos.arkui.stateManagement" + +@Component +struct PropParent { + @PropRef propVar1: string; + @PropRef propVar2?: number; + @PropRef propVar3: boolean; + @PropRef propVar4: undefined; + @PropRef propVar5: null; + @PropRef propVar6: Array | null; + @PropRef propVar7: Map | undefined; + + build() { } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/prop-ref/state-to-prop-ref.ets b/arkui-plugins/test/demo/mock/decorators/prop-ref/state-to-prop-ref.ets new file mode 100644 index 0000000000000000000000000000000000000000..e729a9c7c7c4dc5b77c229091737ef30112a94fb --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/prop-ref/state-to-prop-ref.ets @@ -0,0 +1,54 @@ +/* + * 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 { Component, Text, Button, Column, ClickEvent } from "@ohos.arkui.component" +import { PropRef, State } from "@ohos.arkui.stateManagement" + +@Component +struct CountDownComponent { + @PropRef count: number = 0; + costOfOneAttempt: number = 1; + + build() { + Column() { + if (this.count > 0) { + Text('You have'+ this.count + 'Nuggets left') + } else { + Text('Game over!') + } + Button('Try again').onClick((e: ClickEvent) => { + this.count -= this.costOfOneAttempt; + }) + } + } +} + +@Component +struct ParentComponent { + @State countDownStartValue: number = 10; + + build() { + Column() { + Text('Grant' + this.countDownStartValue + 'nuggets to play.') + Button('+1 - Nuggets in New Game').onClick((e: ClickEvent) => { + this.countDownStartValue += 1; + }) + Button('-1 - Nuggets in New Game').onClick((e: ClickEvent) => { + this.countDownStartValue -= 1; + }) + CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 }) + } + } +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-complex-type.ets b/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-complex-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..1951e82772cbed159254187e75dda626ae97e97b --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-complex-type.ets @@ -0,0 +1,41 @@ +/* + * 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 { Component } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins +import { StoragePropRef } from "@ohos.arkui.stateManagement" + +class Person{ + name: string = '' + constructor(name: string){} +} + +enum Status { + Success = 200, + NotFound = 404, + ServerError = 500 +} + +@Component +struct MyStateSample { + @StoragePropRef('Prop1') arrayB: number[] = [1,2,3]; + @StoragePropRef('Prop2') objectB: Object = {}; + @StoragePropRef('Prop3') dateB: Date = new Date('2021-09-09'); + @StoragePropRef('Prop4') setB: Set = new Set(); + @StoragePropRef('Prop5') mapB: Map = new Map(); + @StoragePropRef('Prop7') classB: Person = new Person("Kevin"); + @StoragePropRef('Prop8') enumB: Status = Status.NotFound; + + build() {} +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-primitive-type.ets b/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-primitive-type.ets new file mode 100644 index 0000000000000000000000000000000000000000..e84494b669f09f4728b6e92586d3972b0494930b --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/storageprop-ref/storageprop-ref-primitive-type.ets @@ -0,0 +1,28 @@ +/* + * 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 { Component } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins +import { StoragePropRef } from "@ohos.arkui.stateManagement" + +@Component +struct MyStateSample { + @StoragePropRef('Prop1') numB: number = 43; + @StoragePropRef('Prop2') stringB: string = 'BB'; + @StoragePropRef('Prop3') booleanB: boolean = false; + @StoragePropRef('Prop4') undefinedB: undefined = undefined; + @StoragePropRef('Prop5') nullB: null = null; + + build() {} +} \ 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 d0f5ac29d50499a8173da1d11a6ccb61832c8924..fa3db797a1deb4e617d0e80c52a9af397476d0d4 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 @@ -50,9 +50,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; 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 ac52cd1e5823253a82f4eeb27ca53abfebb99c25..f65042c92bbddaa9412aff773a07b3a3d8c90659 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 @@ -49,9 +49,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts index 2f3702d00dc6a790f492c9bb0691191b4834e9df..751bfc0bed29b1b0b4e23ffaba44a9d0041c0929 100644 --- a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts @@ -46,9 +46,6 @@ const parsedTransform: Plugins = { const expectedParsedScript: string = ` -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -103,9 +100,6 @@ const expectedBuilderLambdaScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts b/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts index 8e2c2dd05d7ff77e52ab79cbbd288f719d6fbc3e..f9a77f155af46349aae606a2dd648745eaecfc50 100644 --- a/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts @@ -43,9 +43,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts b/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts index 1661bfbde62eca7187cab7ce569be708683ed864..6261ad5d528fcbf90be7e222a349ac309d78c360 100644 --- a/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts @@ -38,10 +38,6 @@ const parsedTransform: Plugins = { }; const expectedParsedcript: string = ` -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, ResourceStr as ResourceStr, Builder as Builder } from "@ohos.arkui.component"; @@ -85,10 +81,6 @@ import { IPropDecoratedVariable as IPropDecoratedVariable } from "arkui.stateMan import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, ResourceStr as ResourceStr, Builder as Builder } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts b/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts index fc931a33162d00f5023afac63ca2e321136b588f..2c925d38b0667fec477007d254f95feeafe451ae 100644 --- a/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts @@ -40,10 +40,6 @@ const parsedTransform: Plugins = { const expectedScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text, WrappedBuilder as WrappedBuilder, Column as Column, ForEach as ForEach } from "@kit.ArkUI"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts index c95268bf16885e28c5f5835a3e0325726b1f55e5..bed12d063ca9608ec71fc5987e3bae456cc668bd 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts @@ -40,10 +40,6 @@ const parsedTransform: Plugins = { const expectedAfterUIScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text } from "@ohos.arkui.component"; @@ -128,8 +124,6 @@ function main() {} const expectedAfterMemoScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "arkui.stateManagement.runtime"; import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts index 814b8c3aee295c3d01fb7c663f1a68bab416355c..36276ba82f94353aa20e4c17b9d0da5d44b3f27c 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts @@ -39,8 +39,6 @@ const parsedTransform: Plugins = { const expectedAfterUIScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; function main() {} @@ -102,8 +100,6 @@ function main() {} const expectedAfterMemoScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "arkui.stateManagement.runtime"; import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts index c16283a4ef9fa1f197f59292bd161444a6c59884..7cbf498a836cba354dad45040d4a192f6b820809 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts @@ -39,8 +39,6 @@ const parsedTransform: Plugins = { const expectedUIScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text, Row as Row } from "@kit.ArkUI"; @@ -139,8 +137,6 @@ function main() {} const expectedMemoScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "arkui.stateManagement.runtime"; import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text, Row as Row } from "@kit.ArkUI"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts index 3ecead48626553fc65ae98091666d645454816d7..7ed01f7269ed4cbda36867d35d984a89494ac6fa 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts @@ -39,9 +39,6 @@ const expectedScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts index 318d1ee717f7352f70b154979ad33c5291a79957..54c8ceac032b11d629a934ada58052a918064849 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts @@ -41,9 +41,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; 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 new file mode 100644 index 0000000000000000000000000000000000000000..9b72b4d35429d6a7aff9f7a24c2ffa34fe47b0af --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts @@ -0,0 +1,282 @@ +/* + * 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 { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const FUNCTION_DIR_PATH: string = 'decorators/custom-dialog'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'base-custom-dialog.ets'), +]; + +const pluginTester = new PluginTester('test basic capability of @CustomDialog', buildConfig); + +const parsedTransform: Plugins = { + name: 'base-custom-dialog', + 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 { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; + +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { TextAttribute as TextAttribute } from "arkui.component.text"; + +import { BaseCustomDialog as BaseCustomDialog } from "arkui.component.customComponent"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Entry as Entry, Button as Button, ClickEvent as ClickEvent } from "@ohos.arkui.component"; + +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 hilog from "@ohos.hilog"; + +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"))); + } + + public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} + + private __backing_aaController?: (CustomDialogController | undefined); + + public get aaController(): (CustomDialogController | undefined) { + return (this.__backing_aaController as (CustomDialogController | undefined)); + } + + public set aaController(value: (CustomDialogController | undefined)) { + this.__backing_aaController = value; + } + + private __backing_text?: IStateDecoratedVariable; + + public get text(): string { + return this.__backing_text!.get(); + } + + public set text(value: string) { + this.__backing_text!.set(value); + } + + private __backing_cancel?: (()=> void); + + public get cancel(): (()=> void) { + return (this.__backing_cancel as (()=> void)); + } + + public set cancel(value: (()=> void)) { + this.__backing_cancel = value; + } + + private __backing_confirm?: (()=> void); + + public get confirm(): (()=> void) { + return (this.__backing_confirm as (()=> void)); + } + + public set confirm(value: (()=> void)) { + this.__backing_confirm = value; + } + + private __backing_hh?: IStateDecoratedVariable; + + public get hh(): string { + return this.__backing_hh!.get(); + } + + public set hh(value: string) { + this.__backing_hh!.set(value); + } + + public __setDialogController__(controller: CustomDialogController): void { + this.__backing_aaController = controller; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Text(@memo() ((instance: TextAttribute): void => { + instance.fontSize(30).height(100); + return; + }), "CustomDialog One", undefined, undefined); + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + if (((this.aaController) != (undefined))) { + this.aaController!.close(); + } + })).margin(20); + return; + }), "Close", undefined, undefined); + })); + } + + private constructor() {} + +} + +@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({ + builder: @memo() (() => { + CustomDialogExample._instantiateImpl(undefined, (() => { + const instance = new CustomDialogExample(); + instance.__setDialogController__((this.dialogController as CustomDialogController)); + return instance; + }), { + cancel: (() => { + this.onCancel(); + }), + confirm: (() => { + this.onAccept(); + }), + }, undefined); + }), + cancel: this.existApp, + autoCancel: true, + alignment: DialogAlignment.Center, + offset: { + dx: 0, + dy: -20, + }, + gridCount: 4, + showInSubWindow: true, + isModal: true, + customStyle: false, + cornerRadius: 10, + focusable: true, + baseComponent: this, + }))); + } + + public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} + + private __backing_dialogController?: (CustomDialogController | null); + + public get dialogController(): (CustomDialogController | null) { + return (this.__backing_dialogController as (CustomDialogController | null)); + } + + public set dialogController(value: (CustomDialogController | null)) { + this.__backing_dialogController = value; + } + + public aboutToDisappear() { + this.dialogController = null; + } + + public onCancel() { + console.info("Callback when the first button is clicked"); + } + + public onAccept() { + console.info("Callback when the second button is clicked"); + } + + public existApp() { + console.info("Click the callback in the blank area"); + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + if (((this.dialogController) != (null))) { + this.dialogController!.open(); + } + })).backgroundColor(0x317aff); + return; + }), "click me", undefined, undefined); + })); + } + + private constructor() {} + +} + +@CustomDialog() export interface __Options_CustomDialogExample { + set aaController(aaController: ((CustomDialogController | undefined) | undefined)) + + get aaController(): ((CustomDialogController | undefined) | undefined) + set text(text: (string | undefined)) + + get text(): (string | undefined) + set __backing_text(__backing_text: (IStateDecoratedVariable | undefined)) + + get __backing_text(): (IStateDecoratedVariable | undefined) + set cancel(cancel: ((()=> void) | undefined)) + + get cancel(): ((()=> void) | undefined) + set confirm(confirm: ((()=> void) | undefined)) + + get confirm(): ((()=> void) | undefined) + set hh(hh: (string | undefined)) + + get hh(): (string | undefined) + set __backing_hh(__backing_hh: (IStateDecoratedVariable | undefined)) + + get __backing_hh(): (IStateDecoratedVariable | undefined) + +} + +@Component() export interface __Options_CustomDialogUser { + set dialogController(dialogController: ((CustomDialogController | null) | undefined)) + + get dialogController(): ((CustomDialogController | null) | undefined) + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test basic capability of @CustomDialog', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd536fdd69c7592323dcf489183a2f8281d08f82 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts @@ -0,0 +1,202 @@ +/* + * 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 { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const FUNCTION_DIR_PATH: string = 'decorators/custom-dialog'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'builder-dialog-options.ets'), +]; + +const pluginTester = new PluginTester('test CustomDialogControllerOptions with @Builder parameter', buildConfig); + +const parsedTransform: Plugins = { + name: 'builder-dialog-options', + parsed: uiTransform().parsed, +}; + +const expectedParsedScript: string = ` +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Builder as Builder } from "@ohos.arkui.component"; + +import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@kit.ArkUI"; + +import hilog from "@ohos.hilog"; + +@Builder() function builder1(str: string) {} + +@Builder() function builder2() {} + +@Component() final struct CustomDialogUser extends CustomComponent { + public dialogController: (CustomDialogController | null) = new CustomDialogController({ + builder: (() => { + builder1("nihao"); + }), + }); + + public build() { + Column(){}; + } + + public constructor() {} + +} + +@Component() final struct CustomDialogUser2 extends CustomComponent { + public dialogController: (CustomDialogController | null) = new CustomDialogController({ + builder: builder2, + }); + + public build() { + Column(){}; + } + + public constructor() {} + +} + +@Component() export interface __Options_CustomDialogUser { + dialogController?: (CustomDialogController | null); + +} + +@Component() export interface __Options_CustomDialogUser2 { + dialogController?: (CustomDialogController | null); + +} +`; + +const expectedCheckedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Builder as Builder } from "@ohos.arkui.component"; + +import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@kit.ArkUI"; + +import hilog from "@ohos.hilog"; + +function main() {} + +@memo() function builder1(str: string) {} + +@memo() function builder2() {} + +@Component() final struct CustomDialogUser extends CustomComponent { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_dialogController = ((({let gensym___50325868 = initializers; + (((gensym___50325868) == (null)) ? undefined : gensym___50325868.dialogController)})) ?? (new CustomDialogController({ + builder: @memo() (() => { + builder1("nihao"); + }), + baseComponent: this, + }))); + } + + public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} + + private __backing_dialogController?: (CustomDialogController | null); + + public get dialogController(): (CustomDialogController | null) { + return (this.__backing_dialogController as (CustomDialogController | null)); + } + + public set dialogController(value: (CustomDialogController | null)) { + this.__backing_dialogController = value; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => {})); + } + + private constructor() {} + +} + +@Component() final struct CustomDialogUser2 extends CustomComponent { + public __initializeStruct(initializers: (__Options_CustomDialogUser2 | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_dialogController = ((({let gensym___51459619 = initializers; + (((gensym___51459619) == (null)) ? undefined : gensym___51459619.dialogController)})) ?? (new CustomDialogController({ + builder: builder2, + baseComponent: this, + }))); + } + + public __updateStruct(initializers: (__Options_CustomDialogUser2 | undefined)): void {} + + private __backing_dialogController?: (CustomDialogController | null); + + public get dialogController(): (CustomDialogController | null) { + return (this.__backing_dialogController as (CustomDialogController | null)); + } + + public set dialogController(value: (CustomDialogController | null)) { + this.__backing_dialogController = value; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => {})); + } + + private constructor() {} + +} + +@Component() export interface __Options_CustomDialogUser { + set dialogController(dialogController: ((CustomDialogController | null) | undefined)) + + get dialogController(): ((CustomDialogController | null) | undefined) + +} + +@Component() export interface __Options_CustomDialogUser2 { + set dialogController(dialogController: ((CustomDialogController | null) | undefined)) + + get dialogController(): ((CustomDialogController | null) | undefined) + +} +`; + +function testParsedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedParsedScript)); +} + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedCheckedScript)); +} + +pluginTester.run( + 'test CustomDialogControllerOptions with @Builder parameter', + [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + { + 'parsed': [testParsedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); 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 new file mode 100644 index 0000000000000000000000000000000000000000..04d08c3eab16e6257520c5db2610eb00aa57d501 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts @@ -0,0 +1,189 @@ +/* + * 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 { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const FUNCTION_DIR_PATH: string = 'decorators/custom-dialog'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'controller-in-build.ets'), +]; + +const pluginTester = new PluginTester('test CustomDialogController in build', buildConfig); + +const parsedTransform: Plugins = { + name: 'controller-in-build', + parsed: uiTransform().parsed, +}; + +const expectedScript: string = ` +import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; + +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 { BaseCustomDialog as BaseCustomDialog } from "arkui.component.customComponent"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Button as Button, ClickEvent as ClickEvent } from "@ohos.arkui.component"; + +import { State as State, Link as Link, Prop as Prop } from "@ohos.arkui.stateManagement"; + +import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@kit.ArkUI"; + +import hilog from "@ohos.hilog"; + +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"))); + } + + public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} + + private __backing_aaController?: (CustomDialogController | undefined); + + public get aaController(): (CustomDialogController | undefined) { + return (this.__backing_aaController as (CustomDialogController | undefined)); + } + + public set aaController(value: (CustomDialogController | undefined)) { + this.__backing_aaController = value; + } + + private __backing_text?: IStateDecoratedVariable; + + public get text(): string { + return this.__backing_text!.get(); + } + + public set text(value: string) { + this.__backing_text!.set(value); + } + + private __backing_hh?: IStateDecoratedVariable; + + public get hh(): string { + return this.__backing_hh!.get(); + } + + public set hh(value: string) { + this.__backing_hh!.set(value); + } + + public __setDialogController__(controller: CustomDialogController): void { + this.__backing_aaController = controller; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Text(undefined, "CustomDialog One", undefined, undefined); + })); + } + + private constructor() {} + +} + +@Component() final struct CustomDialogUser extends CustomComponent { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} + + @memo() public build() { + 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({ + builder: @memo() (() => { + CustomDialogExample._instantiateImpl(undefined, (() => { + const instance = new CustomDialogExample(); + instance.__setDialogController__((gensym___176924847 as CustomDialogController)); + return instance; + }), {}, undefined); + }), + baseComponent: this, + }) + gensym___176924847}); + })).backgroundColor(0x317aff); + return; + }), "click me", undefined, undefined); + })); + } + + private constructor() {} + +} + +@CustomDialog() export interface __Options_CustomDialogExample { + set aaController(aaController: ((CustomDialogController | undefined) | undefined)) + + get aaController(): ((CustomDialogController | undefined) | undefined) + set text(text: (string | undefined)) + + get text(): (string | undefined) + set __backing_text(__backing_text: (IStateDecoratedVariable | undefined)) + + get __backing_text(): (IStateDecoratedVariable | undefined) + set hh(hh: (string | undefined)) + + get hh(): (string | undefined) + set __backing_hh(__backing_hh: (IStateDecoratedVariable | undefined)) + + get __backing_hh(): (IStateDecoratedVariable | undefined) + +} + +@Component() export interface __Options_CustomDialogUser { + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test CustomDialogController in build', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); 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 new file mode 100644 index 0000000000000000000000000000000000000000..c2e0721327d7e280820de36997ec95bfe189a31f --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts @@ -0,0 +1,179 @@ +/* + * 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 { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const FUNCTION_DIR_PATH: string = 'decorators/custom-dialog'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'extends-dialog-controller.ets'), +]; + +const pluginTester = new PluginTester('test extends class of CutomDialogController', buildConfig); + +const parsedTransform: Plugins = { + name: 'extends-dialog-controller', + parsed: uiTransform().parsed, +}; + +const expectedScript: string = ` +import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; + +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { BaseCustomDialog as BaseCustomDialog } from "arkui.component.customComponent"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Entry as Entry, Button as Button, ClickEvent as ClickEvent } from "@ohos.arkui.component"; + +import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogController, CustomDialogControllerOptions as CustomDialogControllerOptions } from "@kit.ArkUI"; + +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)); + } + + public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} + + private __backing_aaController?: (CustomDialogController | undefined); + + public get aaController(): (CustomDialogController | undefined) { + return (this.__backing_aaController as (CustomDialogController | undefined)); + } + + public set aaController(value: (CustomDialogController | undefined)) { + this.__backing_aaController = value; + } + + public __setDialogController__(controller: CustomDialogController): void { + this.__backing_aaController = controller; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => {})); + } + + private constructor() {} + +} + +class DialogControllerV2 extends CustomDialogController { + public options: CustomDialogControllerOptions; + + public constructor(options: CustomDialogControllerOptions) { + super(options); + this.options = options; + } + +} + +class DialogControllerV3 extends DialogControllerV2 { + public options: CustomDialogControllerOptions; + + public constructor(options: CustomDialogControllerOptions) { + super(options); + this.options = options; + } + +} + +@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(({ + gridCount: 4, + showInSubWindow: true, + builder: @memo() (() => { + CustomDialogExample._instantiateImpl(undefined, (() => { + const instance = new CustomDialogExample(); + instance.__setDialogController__((this.dialogController as CustomDialogController)); + return instance; + }), undefined, undefined); + }), + baseComponent: this, + } as CustomDialogControllerOptions)) as DialogControllerV3))); + } + + public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} + + private __backing_dialogController?: (CustomDialogController | null); + + public get dialogController(): (CustomDialogController | null) { + return (this.__backing_dialogController as (CustomDialogController | null)); + } + + public set dialogController(value: (CustomDialogController | null)) { + this.__backing_dialogController = value; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + if (((this.dialogController) != (null))) { + this.dialogController!.open(); + } + })); + return; + }), "click me", undefined, undefined); + })); + } + + private constructor() {} + +} + +@CustomDialog() export interface __Options_CustomDialogExample { + set aaController(aaController: ((CustomDialogController | undefined) | undefined)) + + get aaController(): ((CustomDialogController | undefined) | undefined) + +} + +@Component() export interface __Options_CustomDialogUser { + set dialogController(dialogController: ((CustomDialogController | null) | undefined)) + + get dialogController(): ((CustomDialogController | null) | undefined) + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test extends class of CutomDialogController', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts index a270de494e3f096d057bda0a42a630d9006e8150..62f3f08e27f76c430231a30a6d20cc892a51c2c8 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts @@ -47,9 +47,6 @@ import { LinkSourceType as LinkSourceType } from "arkui.stateManagement.decorato import { ILinkDecoratedVariable as ILinkDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts index 7cea19daeb4d0ca1c5b42a08e9a365f6334fe56a..bd0b32e4b72f4d01a753769b9853aa684b66ba16 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts @@ -46,9 +46,6 @@ import { LinkSourceType as LinkSourceType } from "arkui.stateManagement.decorato import { ILinkDecoratedVariable as ILinkDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts index a507ebd52061f906a5d636684d07045d6f6eef01..0e3f56d43115cfb37be93a9c3f17f9cd1dcaff34 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts @@ -50,9 +50,6 @@ import { ILinkDecoratedVariable as ILinkDecoratedVariable } from "arkui.stateMan import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts index 111874d8cab45adbff9973641a6ffbb6de9d8674..8f4d4fa0ed7fd3d1a10e5891a37b6dfbca88de74 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts @@ -56,9 +56,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts index b211f503cec6b143cd3ef5afe92eed2bd52f72f2..f3261d45b4f8c097370762ecc847656be7447d94 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts @@ -51,9 +51,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts index 8b40cd45d21e2fca1e3419cd0581db0aeafad549..507a09fe3d75d67e8d764c668abc4245a9f9c5a0 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts @@ -50,9 +50,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c52fc362066ff833f4e76fa897b5a051bfc46d4a --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts @@ -0,0 +1,279 @@ +/* + * 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 STORAGEPROP_DIR_PATH: string = 'decorators/localstorageprop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, STORAGEPROP_DIR_PATH, 'localstorageprop-ref-complex-type.ets'), +]; + +const storagePropTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed, +} + +const pluginTester = new PluginTester('test @LocalStoragePropRef complex type transform', buildConfig); + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { ILocalStoragePropRefDecoratedVariable as ILocalStoragePropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { LocalStoragePropRef as LocalStoragePropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + +class Person { + public name: string = ""; + + public constructor(name: string) {} + +} + +final class Status extends BaseEnum { + private readonly #ordinal: int; + + private static () {} + + public constructor(ordinal: int, value: int) { + super(value); + this.#ordinal = ordinal; + } + + public static readonly Success: Status = new Status(0, 200); + + public static readonly NotFound: Status = new Status(1, 404); + + public static readonly ServerError: Status = new Status(2, 500); + + private static readonly #NamesArray: String[] = ["Success", "NotFound", "ServerError"]; + + private static readonly #ValuesArray: int[] = [200, 404, 500]; + + private static readonly #StringValuesArray: String[] = ["200", "404", "500"]; + + private static readonly #ItemsArray: Status[] = [Status.Success, Status.NotFound, Status.ServerError]; + + public getName(): String { + return Status.#NamesArray[this.#ordinal]; + } + + public static getValueOf(name: String): Status { + for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + if (((name) == (Status.#NamesArray[i]))) { + return Status.#ItemsArray[i]; + } + } + throw new Error((("No enum constant Status.") + (name))); + } + + public static fromValue(value: int): Status { + for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + if (((value) == (Status.#ValuesArray[i]))) { + return Status.#ItemsArray[i]; + } + } + throw new Error((("No enum Status with value ") + (value))); + } + + public valueOf(): int { + return Status.#ValuesArray[this.#ordinal]; + } + + public toString(): String { + return Status.#StringValuesArray[this.#ordinal]; + } + + public static values(): Status[] { + return Status.#ItemsArray; + } + + public getOrdinal(): int { + return this.#ordinal; + } + + public static $_get(e: Status): String { + return e.getName(); + } + +} + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_arrayB = STATE_MGMT_FACTORY.makeLocalStoragePropRef>(this, "Prop1", "arrayB", [1, 2, 3], Type.from>()) + this.__backing_objectB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop2", "objectB", {}, Type.from()) + this.__backing_dateB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop3", "dateB", new Date("2021-09-09"), Type.from()) + this.__backing_setB = STATE_MGMT_FACTORY.makeLocalStoragePropRef>(this, "Prop4", "setB", new Set(), Type.from>()) + this.__backing_mapB = STATE_MGMT_FACTORY.makeLocalStoragePropRef>(this, "Prop5", "mapB", new Map(), Type.from>()) + this.__backing_classB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop7", "classB", new Person("Kevin"), Type.from()) + this.__backing_enumB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop8", "enumB", Status.NotFound, Type.from()) + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_arrayB?: ILocalStoragePropRefDecoratedVariable>; + + public get arrayB(): Array { + return this.__backing_arrayB!.get(); + } + + public set arrayB(value: Array) { + this.__backing_arrayB!.set(value); + } + + private __backing_objectB?: ILocalStoragePropRefDecoratedVariable; + + public get objectB(): Object { + return this.__backing_objectB!.get(); + } + + public set objectB(value: Object) { + this.__backing_objectB!.set(value); + } + + private __backing_dateB?: ILocalStoragePropRefDecoratedVariable; + + public get dateB(): Date { + return this.__backing_dateB!.get(); + } + + public set dateB(value: Date) { + this.__backing_dateB!.set(value); + } + + private __backing_setB?: ILocalStoragePropRefDecoratedVariable>; + + public get setB(): Set { + return this.__backing_setB!.get(); + } + + public set setB(value: Set) { + this.__backing_setB!.set(value); + } + + private __backing_mapB?: ILocalStoragePropRefDecoratedVariable>; + + public get mapB(): Map { + return this.__backing_mapB!.get(); + } + + public set mapB(value: Map) { + this.__backing_mapB!.set(value); + } + + private __backing_classB?: ILocalStoragePropRefDecoratedVariable; + + public get classB(): Person { + return this.__backing_classB!.get(); + } + + public set classB(value: Person) { + this.__backing_classB!.set(value); + } + + private __backing_enumB?: ILocalStoragePropRefDecoratedVariable; + + public get enumB(): Status { + return this.__backing_enumB!.get(); + } + + public set enumB(value: Status) { + this.__backing_enumB!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + set arrayB(arrayB: (Array | undefined)) + + get arrayB(): (Array | undefined) + set __backing_arrayB(__backing_arrayB: (ILocalStoragePropRefDecoratedVariable> | undefined)) + + get __backing_arrayB(): (ILocalStoragePropRefDecoratedVariable> | undefined) + set objectB(objectB: (Object | undefined)) + + get objectB(): (Object | undefined) + set __backing_objectB(__backing_objectB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_objectB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set dateB(dateB: (Date | undefined)) + + get dateB(): (Date | undefined) + set __backing_dateB(__backing_dateB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_dateB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set setB(setB: (Set | undefined)) + + get setB(): (Set | undefined) + set __backing_setB(__backing_setB: (ILocalStoragePropRefDecoratedVariable> | undefined)) + + get __backing_setB(): (ILocalStoragePropRefDecoratedVariable> | undefined) + set mapB(mapB: (Map | undefined)) + + get mapB(): (Map | undefined) + set __backing_mapB(__backing_mapB: (ILocalStoragePropRefDecoratedVariable> | undefined)) + + get __backing_mapB(): (ILocalStoragePropRefDecoratedVariable> | undefined) + set classB(classB: (Person | undefined)) + + get classB(): (Person | undefined) + set __backing_classB(__backing_classB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_classB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set enumB(enumB: (Status | undefined)) + + get enumB(): (Status | undefined) + set __backing_enumB(__backing_enumB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_enumB(): (ILocalStoragePropRefDecoratedVariable | undefined) + +} +`; + +function testStoragePropTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @LocalStoragePropRef complex type transform', + [storagePropTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testStoragePropTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..14e3191b48bb15d4a35aa56117e1bbb5ce99d84b --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts @@ -0,0 +1,170 @@ +/* + * 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 STORAGEPROP_DIR_PATH: string = 'decorators/localstorageprop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, STORAGEPROP_DIR_PATH, 'localstorageprop-ref-primitive-type.ets'), +]; + +const storagePropTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed, +} + +const pluginTester = new PluginTester('test @LocalStoragePropRef primitive type transform', buildConfig); + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { ILocalStoragePropRefDecoratedVariable as ILocalStoragePropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { LocalStoragePropRef as LocalStoragePropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_numB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop1", "numB", 43, Type.from()) + this.__backing_stringB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop2", "stringB", "BB", Type.from()) + this.__backing_booleanB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop3", "booleanB", false, Type.from()) + this.__backing_undefinedB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop4", "undefinedB", undefined, Type.from()) + this.__backing_nullB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop5", "nullB", null, Type.from()) + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_numB?: ILocalStoragePropRefDecoratedVariable; + + public get numB(): number { + return this.__backing_numB!.get(); + } + + public set numB(value: number) { + this.__backing_numB!.set(value); + } + + private __backing_stringB?: ILocalStoragePropRefDecoratedVariable; + + public get stringB(): string { + return this.__backing_stringB!.get(); + } + + public set stringB(value: string) { + this.__backing_stringB!.set(value); + } + + private __backing_booleanB?: ILocalStoragePropRefDecoratedVariable; + + public get booleanB(): boolean { + return this.__backing_booleanB!.get(); + } + + public set booleanB(value: boolean) { + this.__backing_booleanB!.set(value); + } + + private __backing_undefinedB?: ILocalStoragePropRefDecoratedVariable; + + public get undefinedB(): undefined { + return this.__backing_undefinedB!.get(); + } + + public set undefinedB(value: undefined) { + this.__backing_undefinedB!.set(value); + } + + private __backing_nullB?: ILocalStoragePropRefDecoratedVariable; + + public get nullB(): null { + return this.__backing_nullB!.get(); + } + + public set nullB(value: null) { + this.__backing_nullB!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + set numB(numB: (number | undefined)) + + get numB(): (number | undefined) + set __backing_numB(__backing_numB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_numB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set stringB(stringB: (string | undefined)) + + get stringB(): (string | undefined) + set __backing_stringB(__backing_stringB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_stringB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set booleanB(booleanB: (boolean | undefined)) + + get booleanB(): (boolean | undefined) + set __backing_booleanB(__backing_booleanB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_booleanB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set undefinedB(undefinedB: (undefined | undefined)) + + get undefinedB(): (undefined | undefined) + set __backing_undefinedB(__backing_undefinedB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_undefinedB(): (ILocalStoragePropRefDecoratedVariable | undefined) + set nullB(nullB: (null | undefined)) + + get nullB(): (null | undefined) + set __backing_nullB(__backing_nullB: (ILocalStoragePropRefDecoratedVariable | undefined)) + + get __backing_nullB(): (ILocalStoragePropRefDecoratedVariable | undefined) + +} +`; + +function testStoragePropTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @LocalStoragePropRef primitive type transform', + [storagePropTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testStoragePropTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts index d832bf9762771c084e587b4bdb392468199044db..9bace1f47ff4bf38d57ae0507b5254b7aee4bb53 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts @@ -57,10 +57,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts index aef8d5ccb2c8754fe1fb27991b780f98354d9506..1b4c2aad509b253fd1183175f5dffe0a97dc7a90 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts @@ -67,10 +67,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Column as Column, Button as Button, ClickEvent as ClickEvent } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts index 0f5144ec94227de65aefdf9ea20fca86615d0da9..c06149a61b99a627200c512ce9d1ccd5a8b513a4 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts index 3f35028ec6e52c52186ca4b11d6398c57c71a500..19cf7c3109959b3204e976239e0d7bdd528fe995 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts index b36744bcdae7a48234894f868bbd3420de1b052c..2f0cc7eb41fca17282ac8add475d43bd5de7970e 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts index e5d7b06cd9ff714b7b1061cc1fa66efdbf1af5d0..8692b04ddd6124ea3fedf5c5b893921a88b001d4 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts index 9f2d7360aebd5519e0dfba58860eafcf71d10ad3..36cc3dd42e4f56fa2ce9a128e13ece5b0d3f49a7 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts @@ -60,10 +60,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts index 8134669430d8b854efa7dfa934143d6d6b68130d..b01f4d7b33784a92d3ec1420b45c4359a782ad9f 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts index 2352837bbd6299b7b8f151d712d9e6c81cef0003..cf679627fd287ac76c5ab541dd0a9abddcaf4738 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts index e82e823fc96ac5c12764516079689d761298c770..9d112e2ef16c7127669d2fe164d4469731ab229e 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts index a62942b8b560fff5f071f32d6181c1fd381531f2..163b8d398a49078d216f3f24298b9e8386655100 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts @@ -55,10 +55,6 @@ import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement. import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b788197b52375dfc7b888c04c3bf777c92ffb7b7 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts @@ -0,0 +1,198 @@ +/* + * 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 { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'decorators/prop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, 'prop-ref-basic-type.ets'), +]; + +const pluginTester = new PluginTester('test basic type @PropRef decorated variables transformation', buildConfig); + +const parsedTransform: Plugins = { + name: 'prop-ref-basic-type', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + + + +@Component() final struct PropParent extends CustomComponent { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", ((({let gensym___95172135 = initializers; + (((gensym___95172135) == (null)) ? undefined : gensym___95172135.propVar1)})) ?? ("propVar1"))); + this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef(this, "propVar2", ((({let gensym___222490386 = initializers; + (((gensym___222490386) == (null)) ? undefined : gensym___222490386.propVar2)})) ?? (50))); + this.__backing_propVar3 = STATE_MGMT_FACTORY.makePropRef(this, "propVar3", ((({let gensym___201781257 = initializers; + (((gensym___201781257) == (null)) ? undefined : gensym___201781257.propVar3)})) ?? (true))); + this.__backing_propVar4 = STATE_MGMT_FACTORY.makePropRef(this, "propVar4", ((({let gensym___22028950 = initializers; + (((gensym___22028950) == (null)) ? undefined : gensym___22028950.propVar4)})) ?? (undefined))); + this.__backing_propVar5 = STATE_MGMT_FACTORY.makePropRef(this, "propVar5", ((({let gensym___54872258 = initializers; + (((gensym___54872258) == (null)) ? undefined : gensym___54872258.propVar5)})) ?? (null))); + } + + public __updateStruct(initializers: (__Options_PropParent | undefined)): void { + if (((({let gensym___67969738 = initializers; + (((gensym___67969738) == (null)) ? undefined : gensym___67969738.propVar1)})) !== (undefined))) { + this.__backing_propVar1!.update((initializers!.propVar1 as string)); + } + if (((({let gensym___52350476 = initializers; + (((gensym___52350476) == (null)) ? undefined : gensym___52350476.propVar2)})) !== (undefined))) { + this.__backing_propVar2!.update((initializers!.propVar2 as number)); + } + if (((({let gensym___103864283 = initializers; + (((gensym___103864283) == (null)) ? undefined : gensym___103864283.propVar3)})) !== (undefined))) { + this.__backing_propVar3!.update((initializers!.propVar3 as boolean)); + } + if (((({let gensym___175155715 = initializers; + (((gensym___175155715) == (null)) ? undefined : gensym___175155715.propVar4)})) !== (undefined))) { + this.__backing_propVar4!.update((initializers!.propVar4 as undefined)); + } + if (((({let gensym___134530703 = initializers; + (((gensym___134530703) == (null)) ? undefined : gensym___134530703.propVar5)})) !== (undefined))) { + this.__backing_propVar5!.update((initializers!.propVar5 as null)); + } + } + + private __backing_propVar1?: IPropRefDecoratedVariable; + + public get propVar1(): string { + return this.__backing_propVar1!.get(); + } + + public set propVar1(value: string) { + this.__backing_propVar1!.set(value); + } + + private __backing_propVar2?: IPropRefDecoratedVariable; + + public get propVar2(): number { + return this.__backing_propVar2!.get(); + } + + public set propVar2(value: number) { + this.__backing_propVar2!.set(value); + } + + private __backing_propVar3?: IPropRefDecoratedVariable; + + public get propVar3(): boolean { + return this.__backing_propVar3!.get(); + } + + public set propVar3(value: boolean) { + this.__backing_propVar3!.set(value); + } + + private __backing_propVar4?: IPropRefDecoratedVariable; + + public get propVar4(): undefined { + return this.__backing_propVar4!.get(); + } + + public set propVar4(value: undefined) { + this.__backing_propVar4!.set(value); + } + + private __backing_propVar5?: IPropRefDecoratedVariable; + + public get propVar5(): null { + return this.__backing_propVar5!.get(); + } + + public set propVar5(value: null) { + this.__backing_propVar5!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_PropParent { + set propVar1(propVar1: (string | undefined)) + + get propVar1(): (string | undefined) + set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) + set propVar2(propVar2: (number | undefined)) + + get propVar2(): (number | undefined) + set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar2(): (IPropRefDecoratedVariable | undefined) + set propVar3(propVar3: (boolean | undefined)) + + get propVar3(): (boolean | undefined) + set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) + set propVar4(propVar4: (undefined | undefined)) + + get propVar4(): (undefined | undefined) + set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar4(): (IPropRefDecoratedVariable | undefined) + set propVar5(propVar5: (null | undefined)) + + get propVar5(): (null | undefined) + set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar5(): (IPropRefDecoratedVariable | undefined) + +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test basic type @PropRef decorated variables transformation', + [parsedTransform, structNoRecheck, recheck], + { + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0a73384ba5a422c16944bf920ff9a0709ed3e61 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts @@ -0,0 +1,427 @@ +/* + * 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 { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'decorators/prop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, 'prop-ref-complex-type.ets'), +]; + +const pluginTester = new PluginTester('test complex type @PropRef decorated variables transformation', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsed-trans', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + +class Per { + public num: number; + + public constructor(num: number) { + this.num = num; + } + +} + +final class PropType extends BaseEnum { + private readonly #ordinal: int; + + private static () {} + + public constructor(ordinal: int, value: int) { + super(value); + this.#ordinal = ordinal; + } + + public static readonly TYPE1: PropType = new PropType(0, 0); + + public static readonly TYPE2: PropType = new PropType(1, 1); + + public static readonly TYPE3: PropType = new PropType(2, 3); + + private static readonly #NamesArray: String[] = ["TYPE1", "TYPE2", "TYPE3"]; + + private static readonly #ValuesArray: int[] = [0, 1, 3]; + + private static readonly #StringValuesArray: String[] = ["0", "1", "3"]; + + private static readonly #ItemsArray: PropType[] = [PropType.TYPE1, PropType.TYPE2, PropType.TYPE3]; + + public getName(): String { + return PropType.#NamesArray[this.#ordinal]; + } + + public static getValueOf(name: String): PropType { + for (let i = 0;((i) < (PropType.#NamesArray.length));(++i)) { + if (((name) == (PropType.#NamesArray[i]))) { + return PropType.#ItemsArray[i]; + } + } + throw new Error((("No enum constant PropType.") + (name))); + } + + public static fromValue(value: int): PropType { + for (let i = 0;((i) < (PropType.#ValuesArray.length));(++i)) { + if (((value) == (PropType.#ValuesArray[i]))) { + return PropType.#ItemsArray[i]; + } + } + throw new Error((("No enum PropType with value ") + (value))); + } + + public valueOf(): int { + return PropType.#ValuesArray[this.#ordinal]; + } + + public toString(): String { + return PropType.#StringValuesArray[this.#ordinal]; + } + + public static values(): PropType[] { + return PropType.#ItemsArray; + } + + public getOrdinal(): int { + return this.#ordinal; + } + + public static $_get(e: PropType): String { + return e.getName(); + } + +} + +@Component() final struct Parent extends CustomComponent { + public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", ((({let gensym___95172135 = initializers; + (((gensym___95172135) == (null)) ? undefined : gensym___95172135.propVar1)})) ?? (new Per(6)))); + this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar2", ((({let gensym___222490386 = initializers; + (((gensym___222490386) == (null)) ? undefined : gensym___222490386.propVar2)})) ?? (new Array(3, 6, 8)))); + this.__backing_propVar3 = STATE_MGMT_FACTORY.makePropRef(this, "propVar3", ((({let gensym___201781257 = initializers; + (((gensym___201781257) == (null)) ? undefined : gensym___201781257.propVar3)})) ?? (PropType.TYPE3))); + this.__backing_propVar4 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar4", ((({let gensym___22028950 = initializers; + (((gensym___22028950) == (null)) ? undefined : gensym___22028950.propVar4)})) ?? (new Set(new Array("aa", "bb"))))); + this.__backing_propVar5 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar5", ((({let gensym___54872258 = initializers; + (((gensym___54872258) == (null)) ? undefined : gensym___54872258.propVar5)})) ?? ([true, false]))); + this.__backing_propVar6 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar6", ((({let gensym___128760941 = initializers; + (((gensym___128760941) == (null)) ? undefined : gensym___128760941.propVar6)})) ?? (new Array(new Per(7), new Per(11))))); + this.__backing_propVar7 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar7", ((({let gensym___30534085 = initializers; + (((gensym___30534085) == (null)) ? undefined : gensym___30534085.propVar7)})) ?? ([new Per(7), new Per(11)]))); + this.__backing_propVar8 = STATE_MGMT_FACTORY.makePropRef<((sr: string)=> void)>(this, "propVar8", ((({let gensym___12471776 = initializers; + (((gensym___12471776) == (null)) ? undefined : gensym___12471776.propVar8)})) ?? (((sr: string) => {})))); + this.__backing_propVar9 = STATE_MGMT_FACTORY.makePropRef(this, "propVar9", ((({let gensym___123472108 = initializers; + (((gensym___123472108) == (null)) ? undefined : gensym___123472108.propVar9)})) ?? (new Date("2025-4-23")))); + this.__backing_propVar10 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar10", ((({let gensym___147847012 = initializers; + (((gensym___147847012) == (null)) ? undefined : gensym___147847012.propVar10)})) ?? (new Map([[0, new Per(7)], [1, new Per(10)]])))); + this.__backing_propVar11 = STATE_MGMT_FACTORY.makePropRef<(string | number)>(this, "propVar11", ((({let gensym___117026760 = initializers; + (((gensym___117026760) == (null)) ? undefined : gensym___117026760.propVar11)})) ?? (0.0))); + this.__backing_propVar12 = STATE_MGMT_FACTORY.makePropRef<(Set | Per)>(this, "propVar12", ((({let gensym___220245132 = initializers; + (((gensym___220245132) == (null)) ? undefined : gensym___220245132.propVar12)})) ?? (new Per(6)))); + } + + public __updateStruct(initializers: (__Options_Parent | undefined)): void { + if (((({let gensym___67969738 = initializers; + (((gensym___67969738) == (null)) ? undefined : gensym___67969738.propVar1)})) !== (undefined))) { + this.__backing_propVar1!.update((initializers!.propVar1 as Per)); + } + if (((({let gensym___52350476 = initializers; + (((gensym___52350476) == (null)) ? undefined : gensym___52350476.propVar2)})) !== (undefined))) { + this.__backing_propVar2!.update((initializers!.propVar2 as Array)); + } + if (((({let gensym___103864283 = initializers; + (((gensym___103864283) == (null)) ? undefined : gensym___103864283.propVar3)})) !== (undefined))) { + this.__backing_propVar3!.update((initializers!.propVar3 as PropType)); + } + if (((({let gensym___175155715 = initializers; + (((gensym___175155715) == (null)) ? undefined : gensym___175155715.propVar4)})) !== (undefined))) { + this.__backing_propVar4!.update((initializers!.propVar4 as Set)); + } + if (((({let gensym___134530703 = initializers; + (((gensym___134530703) == (null)) ? undefined : gensym___134530703.propVar5)})) !== (undefined))) { + this.__backing_propVar5!.update((initializers!.propVar5 as Array)); + } + if (((({let gensym___211600890 = initializers; + (((gensym___211600890) == (null)) ? undefined : gensym___211600890.propVar6)})) !== (undefined))) { + this.__backing_propVar6!.update((initializers!.propVar6 as Array)); + } + if (((({let gensym___124229427 = initializers; + (((gensym___124229427) == (null)) ? undefined : gensym___124229427.propVar7)})) !== (undefined))) { + this.__backing_propVar7!.update((initializers!.propVar7 as Array)); + } + if (((({let gensym___248056380 = initializers; + (((gensym___248056380) == (null)) ? undefined : gensym___248056380.propVar8)})) !== (undefined))) { + this.__backing_propVar8!.update((initializers!.propVar8 as ((sr: string)=> void))); + } + if (((({let gensym___55399278 = initializers; + (((gensym___55399278) == (null)) ? undefined : gensym___55399278.propVar9)})) !== (undefined))) { + this.__backing_propVar9!.update((initializers!.propVar9 as Date)); + } + if (((({let gensym___125042885 = initializers; + (((gensym___125042885) == (null)) ? undefined : gensym___125042885.propVar10)})) !== (undefined))) { + this.__backing_propVar10!.update((initializers!.propVar10 as Map)); + } + if (((({let gensym___2015283 = initializers; + (((gensym___2015283) == (null)) ? undefined : gensym___2015283.propVar11)})) !== (undefined))) { + this.__backing_propVar11!.update((initializers!.propVar11 as (string | number))); + } + if (((({let gensym___39009414 = initializers; + (((gensym___39009414) == (null)) ? undefined : gensym___39009414.propVar12)})) !== (undefined))) { + this.__backing_propVar12!.update((initializers!.propVar12 as (Set | Per))); + } + } + + private __backing_propVar1?: IPropRefDecoratedVariable; + + public get propVar1(): Per { + return this.__backing_propVar1!.get(); + } + + public set propVar1(value: Per) { + this.__backing_propVar1!.set(value); + } + + private __backing_propVar2?: IPropRefDecoratedVariable>; + + public get propVar2(): Array { + return this.__backing_propVar2!.get(); + } + + public set propVar2(value: Array) { + this.__backing_propVar2!.set(value); + } + + private __backing_propVar3?: IPropRefDecoratedVariable; + + public get propVar3(): PropType { + return this.__backing_propVar3!.get(); + } + + public set propVar3(value: PropType) { + this.__backing_propVar3!.set(value); + } + + private __backing_propVar4?: IPropRefDecoratedVariable>; + + public get propVar4(): Set { + return this.__backing_propVar4!.get(); + } + + public set propVar4(value: Set) { + this.__backing_propVar4!.set(value); + } + + private __backing_propVar5?: IPropRefDecoratedVariable>; + + public get propVar5(): Array { + return this.__backing_propVar5!.get(); + } + + public set propVar5(value: Array) { + this.__backing_propVar5!.set(value); + } + + private __backing_propVar6?: IPropRefDecoratedVariable>; + + public get propVar6(): Array { + return this.__backing_propVar6!.get(); + } + + public set propVar6(value: Array) { + this.__backing_propVar6!.set(value); + } + + private __backing_propVar7?: IPropRefDecoratedVariable>; + + public get propVar7(): Array { + return this.__backing_propVar7!.get(); + } + + public set propVar7(value: Array) { + this.__backing_propVar7!.set(value); + } + + private __backing_propVar8?: IPropRefDecoratedVariable<((sr: string)=> void)>; + + public get propVar8(): ((sr: string)=> void) { + return this.__backing_propVar8!.get(); + } + + public set propVar8(value: ((sr: string)=> void)) { + this.__backing_propVar8!.set(value); + } + + private __backing_propVar9?: IPropRefDecoratedVariable; + + public get propVar9(): Date { + return this.__backing_propVar9!.get(); + } + + public set propVar9(value: Date) { + this.__backing_propVar9!.set(value); + } + + private __backing_propVar10?: IPropRefDecoratedVariable>; + + public get propVar10(): Map { + return this.__backing_propVar10!.get(); + } + + public set propVar10(value: Map) { + this.__backing_propVar10!.set(value); + } + + private __backing_propVar11?: IPropRefDecoratedVariable<(string | number)>; + + public get propVar11(): (string | number) { + return this.__backing_propVar11!.get(); + } + + public set propVar11(value: (string | number)) { + this.__backing_propVar11!.set(value); + } + + private __backing_propVar12?: IPropRefDecoratedVariable<(Set | Per)>; + + public get propVar12(): (Set | Per) { + return this.__backing_propVar12!.get(); + } + + public set propVar12(value: (Set | Per)) { + this.__backing_propVar12!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_Parent { + set propVar1(propVar1: (Per | undefined)) + + get propVar1(): (Per | undefined) + set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) + set propVar2(propVar2: (Array | undefined)) + + get propVar2(): (Array | undefined) + set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar2(): (IPropRefDecoratedVariable> | undefined) + set propVar3(propVar3: (PropType | undefined)) + + get propVar3(): (PropType | undefined) + set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) + set propVar4(propVar4: (Set | undefined)) + + get propVar4(): (Set | undefined) + set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar4(): (IPropRefDecoratedVariable> | undefined) + set propVar5(propVar5: (Array | undefined)) + + get propVar5(): (Array | undefined) + set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar5(): (IPropRefDecoratedVariable> | undefined) + set propVar6(propVar6: (Array | undefined)) + + get propVar6(): (Array | undefined) + set __backing_propVar6(__backing_propVar6: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar6(): (IPropRefDecoratedVariable> | undefined) + set propVar7(propVar7: (Array | undefined)) + + get propVar7(): (Array | undefined) + set __backing_propVar7(__backing_propVar7: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar7(): (IPropRefDecoratedVariable> | undefined) + set propVar8(propVar8: (((sr: string)=> void) | undefined)) + + get propVar8(): (((sr: string)=> void) | undefined) + set __backing_propVar8(__backing_propVar8: (IPropRefDecoratedVariable<((sr: string)=> void)> | undefined)) + + get __backing_propVar8(): (IPropRefDecoratedVariable<((sr: string)=> void)> | undefined) + set propVar9(propVar9: (Date | undefined)) + + get propVar9(): (Date | undefined) + set __backing_propVar9(__backing_propVar9: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar9(): (IPropRefDecoratedVariable | undefined) + set propVar10(propVar10: (Map | undefined)) + + get propVar10(): (Map | undefined) + set __backing_propVar10(__backing_propVar10: (IPropRefDecoratedVariable> | undefined)) + + get __backing_propVar10(): (IPropRefDecoratedVariable> | undefined) + set propVar11(propVar11: ((string | number) | undefined)) + + get propVar11(): ((string | number) | undefined) + set __backing_propVar11(__backing_propVar11: (IPropRefDecoratedVariable<(string | number)> | undefined)) + + get __backing_propVar11(): (IPropRefDecoratedVariable<(string | number)> | undefined) + set propVar12(propVar12: ((Set | Per) | undefined)) + + get propVar12(): ((Set | Per) | undefined) + set __backing_propVar12(__backing_propVar12: (IPropRefDecoratedVariable<(Set | Per)> | undefined)) + + get __backing_propVar12(): (IPropRefDecoratedVariable<(Set | Per)> | undefined) + +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test complex type @PropRef decorated variables transformation', + [parsedTransform, structNoRecheck, recheck], + { + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c078ab4373e37272f532c1e466d895c6401f97ac --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts @@ -0,0 +1,285 @@ +/* + * 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 { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'decorators/prop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, 'prop-ref-without-initialization.ets'), +]; + +const pluginTester = new PluginTester('test @PropRef decorated variables transformation without initialization', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsed-trans', + parsed: uiTransform().parsed +}; + +const expectedParsedScript: string = ` +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; + +@Component() final struct PropParent extends CustomComponent { + @PropRef() public propVar1!: string; + + @PropRef() public propVar2?: (number | undefined); + + @PropRef() public propVar3!: boolean; + + @PropRef() public propVar4?: undefined; + + @PropRef() public propVar5?: null; + + @PropRef() public propVar6?: (Array | null); + + @PropRef() public propVar7?: (Map | undefined); + + public build() {} + + public constructor() {} + +} + +@Component() export interface __Options_PropParent { + propVar1?: string; + @PropRef() __backing_propVar1?: string; + propVar2?: (number | undefined); + @PropRef() __backing_propVar2?: (number | undefined); + propVar3?: boolean; + @PropRef() __backing_propVar3?: boolean; + propVar4?: undefined; + @PropRef() __backing_propVar4?: undefined; + propVar5?: null; + @PropRef() __backing_propVar5?: null; + propVar6?: (Array | null); + @PropRef() __backing_propVar6?: (Array | null); + propVar7?: (Map | undefined); + @PropRef() __backing_propVar7?: (Map | undefined); + +} +`; + +const expectedCheckedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + +@Component() final struct PropParent extends CustomComponent { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", (initializers!.propVar1 as string)); + this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef<(number | undefined)>(this, "propVar2", (initializers!.propVar2 as (number | undefined))); + this.__backing_propVar3 = STATE_MGMT_FACTORY.makePropRef(this, "propVar3", (initializers!.propVar3 as boolean)); + this.__backing_propVar4 = STATE_MGMT_FACTORY.makePropRef(this, "propVar4", (initializers!.propVar4 as undefined)); + this.__backing_propVar5 = STATE_MGMT_FACTORY.makePropRef(this, "propVar5", (initializers!.propVar5 as null)); + this.__backing_propVar6 = STATE_MGMT_FACTORY.makePropRef<(Array | null)>(this, "propVar6", (initializers!.propVar6 as (Array | null))); + this.__backing_propVar7 = STATE_MGMT_FACTORY.makePropRef<(Map | undefined)>(this, "propVar7", (initializers!.propVar7 as (Map | undefined))); + } + + public __updateStruct(initializers: (__Options_PropParent | undefined)): void { + if (((({let gensym___67969738 = initializers; + (((gensym___67969738) == (null)) ? undefined : gensym___67969738.propVar1)})) !== (undefined))) { + this.__backing_propVar1!.update((initializers!.propVar1 as string)); + } + if (((({let gensym___52350476 = initializers; + (((gensym___52350476) == (null)) ? undefined : gensym___52350476.propVar2)})) !== (undefined))) { + this.__backing_propVar2!.update((initializers!.propVar2 as (number | undefined))); + } + if (((({let gensym___103864283 = initializers; + (((gensym___103864283) == (null)) ? undefined : gensym___103864283.propVar3)})) !== (undefined))) { + this.__backing_propVar3!.update((initializers!.propVar3 as boolean)); + } + if (((({let gensym___175155715 = initializers; + (((gensym___175155715) == (null)) ? undefined : gensym___175155715.propVar4)})) !== (undefined))) { + this.__backing_propVar4!.update((initializers!.propVar4 as undefined)); + } + if (((({let gensym___134530703 = initializers; + (((gensym___134530703) == (null)) ? undefined : gensym___134530703.propVar5)})) !== (undefined))) { + this.__backing_propVar5!.update((initializers!.propVar5 as null)); + } + if (((({let gensym___211600890 = initializers; + (((gensym___211600890) == (null)) ? undefined : gensym___211600890.propVar6)})) !== (undefined))) { + this.__backing_propVar6!.update((initializers!.propVar6 as (Array | null))); + } + if (((({let gensym___124229427 = initializers; + (((gensym___124229427) == (null)) ? undefined : gensym___124229427.propVar7)})) !== (undefined))) { + this.__backing_propVar7!.update((initializers!.propVar7 as (Map | undefined))); + } + } + + private __backing_propVar1?: IPropRefDecoratedVariable; + + public get propVar1(): string { + return this.__backing_propVar1!.get(); + } + + public set propVar1(value: string) { + this.__backing_propVar1!.set(value); + } + + private __backing_propVar2?: IPropRefDecoratedVariable<(number | undefined)>; + + public get propVar2(): (number | undefined) { + return this.__backing_propVar2!.get(); + } + + public set propVar2(value: (number | undefined)) { + this.__backing_propVar2!.set(value); + } + + private __backing_propVar3?: IPropRefDecoratedVariable; + + public get propVar3(): boolean { + return this.__backing_propVar3!.get(); + } + + public set propVar3(value: boolean) { + this.__backing_propVar3!.set(value); + } + + private __backing_propVar4?: IPropRefDecoratedVariable; + + public get propVar4(): undefined { + return this.__backing_propVar4!.get(); + } + + public set propVar4(value: undefined) { + this.__backing_propVar4!.set(value); + } + + private __backing_propVar5?: IPropRefDecoratedVariable; + + public get propVar5(): null { + return this.__backing_propVar5!.get(); + } + + public set propVar5(value: null) { + this.__backing_propVar5!.set(value); + } + + private __backing_propVar6?: IPropRefDecoratedVariable<(Array | null)>; + + public get propVar6(): (Array | null) { + return this.__backing_propVar6!.get(); + } + + public set propVar6(value: (Array | null)) { + this.__backing_propVar6!.set(value); + } + + private __backing_propVar7?: IPropRefDecoratedVariable<(Map | undefined)>; + + public get propVar7(): (Map | undefined) { + return this.__backing_propVar7!.get(); + } + + public set propVar7(value: (Map | undefined)) { + this.__backing_propVar7!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_PropParent { + set propVar1(propVar1: (string | undefined)) + + get propVar1(): (string | undefined) + set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) + set propVar2(propVar2: ((number | undefined) | undefined)) + + get propVar2(): ((number | undefined) | undefined) + set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable<(number | undefined)> | undefined)) + + get __backing_propVar2(): (IPropRefDecoratedVariable<(number | undefined)> | undefined) + set propVar3(propVar3: (boolean | undefined)) + + get propVar3(): (boolean | undefined) + set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) + set propVar4(propVar4: (undefined | undefined)) + + get propVar4(): (undefined | undefined) + set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar4(): (IPropRefDecoratedVariable | undefined) + set propVar5(propVar5: (null | undefined)) + + get propVar5(): (null | undefined) + set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable | undefined)) + + get __backing_propVar5(): (IPropRefDecoratedVariable | undefined) + set propVar6(propVar6: ((Array | null) | undefined)) + + get propVar6(): ((Array | null) | undefined) + set __backing_propVar6(__backing_propVar6: (IPropRefDecoratedVariable<(Array | null)> | undefined)) + + get __backing_propVar6(): (IPropRefDecoratedVariable<(Array | null)> | undefined) + set propVar7(propVar7: ((Map | undefined) | undefined)) + + get propVar7(): ((Map | undefined) | undefined) + set __backing_propVar7(__backing_propVar7: (IPropRefDecoratedVariable<(Map | undefined)> | undefined)) + + get __backing_propVar7(): (IPropRefDecoratedVariable<(Map | undefined)> | undefined) + +} +`; + +function testParsedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedParsedScript)); +} + +function testheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedCheckedScript)); +} + +pluginTester.run( + 'test @PropRef decorated variables transformation without initialization', + [parsedTransform, structNoRecheck, recheck], + { + 'parsed': [testParsedTransformer], + 'checked:struct-no-recheck': [testheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..80ffe476f567ce33f5cbced40f36244c91cdd232 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts @@ -0,0 +1,197 @@ +/* + * 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 BUILDER_LAMBDA_DIR_PATH: string = 'decorators/prop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, 'state-to-prop-ref.ets'), +]; + +const pluginTester = new PluginTester('test @PropRef decorated variables passing', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component, Text as Text, Button as Button, Column as Column, ClickEvent as ClickEvent } from "@ohos.arkui.component"; + +import { PropRef as PropRef, State as State } from "@ohos.arkui.stateManagement"; + +function main() {} + +@Component() final struct CountDownComponent extends CustomComponent { + public __initializeStruct(initializers: (__Options_CountDownComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_count = STATE_MGMT_FACTORY.makePropRef(this, "count", ((({let gensym___58710805 = initializers; + (((gensym___58710805) == (null)) ? undefined : gensym___58710805.count)})) ?? (0))); + this.__backing_costOfOneAttempt = ((({let gensym___88948111 = initializers; + (((gensym___88948111) == (null)) ? undefined : gensym___88948111.costOfOneAttempt)})) ?? (1)); + } + + public __updateStruct(initializers: (__Options_CountDownComponent | undefined)): void { + if (((({let gensym___188547633 = initializers; + (((gensym___188547633) == (null)) ? undefined : gensym___188547633.count)})) !== (undefined))) { + this.__backing_count!.update((initializers!.count as number)); + } + } + + private __backing_count?: IPropRefDecoratedVariable; + + public get count(): number { + return this.__backing_count!.get(); + } + + public set count(value: number) { + this.__backing_count!.set(value); + } + + private __backing_costOfOneAttempt?: number; + + public get costOfOneAttempt(): number { + return (this.__backing_costOfOneAttempt as number); + } + + public set costOfOneAttempt(value: number) { + this.__backing_costOfOneAttempt = value; + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + if (((this.count) > (0))) { + Text(undefined, (((("You have") + (this.count))) + ("Nuggets left")), undefined, undefined); + } else { + Text(undefined, "Game over!", undefined, undefined); + } + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + this.count -= this.costOfOneAttempt; + })); + return; + }), "Try again", undefined, undefined); + })); + } + + private constructor() {} + +} + +@Component() final struct ParentComponent extends CustomComponent { + public __initializeStruct(initializers: (__Options_ParentComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_countDownStartValue = STATE_MGMT_FACTORY.makeState(this, "countDownStartValue", ((({let gensym___249912438 = initializers; + (((gensym___249912438) == (null)) ? undefined : gensym___249912438.countDownStartValue)})) ?? (10))); + } + + public __updateStruct(initializers: (__Options_ParentComponent | undefined)): void {} + + private __backing_countDownStartValue?: IStateDecoratedVariable; + + public get countDownStartValue(): number { + return this.__backing_countDownStartValue!.get(); + } + + public set countDownStartValue(value: number) { + this.__backing_countDownStartValue!.set(value); + } + + @memo() public build() { + Column(undefined, undefined, @memo() (() => { + Text(undefined, (((("Grant") + (this.countDownStartValue))) + ("nuggets to play.")), undefined, undefined); + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + this.countDownStartValue += 1; + })); + return; + }), "+1 - Nuggets in New Game", undefined, undefined); + Button(@memo() ((instance: ButtonAttribute): void => { + instance.onClick(((e: ClickEvent) => { + this.countDownStartValue -= 1; + })); + return; + }), "-1 - Nuggets in New Game", undefined, undefined); + CountDownComponent._instantiateImpl(undefined, (() => { + return new CountDownComponent(); + }), { + count: this.countDownStartValue, + costOfOneAttempt: 2, + }, undefined, undefined); + })); + } + + private constructor() {} + +} + +@Component() export interface __Options_CountDownComponent { + set count(count: (number | undefined)) + + get count(): (number | undefined) + set __backing_count(__backing_count: (IPropRefDecoratedVariable | undefined)) + + get __backing_count(): (IPropRefDecoratedVariable | undefined) + set costOfOneAttempt(costOfOneAttempt: (number | undefined)) + + get costOfOneAttempt(): (number | undefined) + +} + +@Component() export interface __Options_ParentComponent { + set countDownStartValue(countDownStartValue: (number | undefined)) + + get countDownStartValue(): (number | undefined) + set __backing_countDownStartValue(__backing_countDownStartValue: (IStateDecoratedVariable | undefined)) + + get __backing_countDownStartValue(): (IStateDecoratedVariable | undefined) + +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @PropRef decorated variables passing', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts index 048e585b9b6fe3522c74934a2cb7fe93abfc0f22..d8584fd5fed82a2855f1fbaea2bc803db8f927e9 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts @@ -45,10 +45,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { IPropDecoratedVariable as IPropDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts index 68dc70cdef1a37603974f01469f8396b3897819d..e108af26c0af2c409d0fb48666b3b6dbf4f23e15 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts @@ -44,9 +44,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { IPropDecoratedVariable as IPropDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts index 620bd9884aedd66cff9d10617dc9117009a53c70..9ee9f8d89e1a5cad44edb93bf1590107fdada1d1 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts @@ -48,9 +48,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts index 6866b674f07bf06b805cc48e73b3a1287160c847..453a2c24af11172158a83f10ca0347f518455853 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts @@ -44,9 +44,6 @@ import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.st import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts index 9734b09b8dee6b35f1a501966470312b631fc7f4..30f9174a540fdee8b50f93f0e6622cfe413fc893 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts @@ -44,9 +44,6 @@ import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.st import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts index c7f6f689b2ed49bbc24d5353c950b42835e02155..a58210c096e6e497e3070ed491c15694f22d4d6a 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts @@ -44,9 +44,6 @@ import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.st import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts index 643f1955b746eb9274a35b2db1f17e6ed9f6740c..f083b5e9131ffa473742eb42e733f47819e6ad21 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts @@ -48,9 +48,6 @@ import { ImageAttribute as ImageAttribute } from "arkui.component.image"; import { _r as _r } from "arkui.component.resources"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts index 89b0c4750721f5b34a7d114f845f3b4728471aaa..db246e5824ddc43c9c6dbe1120fdbe2ac408ca3f 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts @@ -41,8 +41,6 @@ const expectedScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; import { _rawfile as _rawfile } from "arkui.component.resources"; import { _r as _r } from "arkui.component.resources"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, $r as $r, $rawfile as $rawfile, Column as Column, Text as Text, Image as Image, Resource as Resource } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index 004ae0a02899cb64f8104f34f78e19f47c5e9074..6b65444af55b5a19ddc7fa6c158a723e361457b4 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -46,9 +46,6 @@ import { IPropDecoratedVariable as IPropDecoratedVariable } from "arkui.stateMan import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts index e3f98d4159c59c420350875c8627589b1ca50cef..21861a469a82bdd4a991ad752df76072273fef9f 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts @@ -57,9 +57,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts index c47bd027b7b07e0346803f7752b3ae88a41393f6..5eaa66172750a071d6d09ebd2db5eb96c8377e65 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts @@ -45,9 +45,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts index cdd84ec17c02276bfadc182b91cd2724b9416b9f..d53dcb99ec1b9b9138bf5503cb66896fc0433b26 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts @@ -44,9 +44,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts index b470b7a1068dd37d4298a312f3f04ae11dd9263a..09310a680a09e9e00d1b8cec60af3181d182e530 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts @@ -45,9 +45,6 @@ import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateM import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts index b6d7d10b2ed230be50ef4305501e1c4c0b77d78e..8216a6a04ef4d1408c4c7f253204f19faa0691c2 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts @@ -45,8 +45,6 @@ import { TextAttribute as TextAttribute } 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 { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Column as Column, Text as Text, ClickEvent as ClickEvent } from "@ohos.arkui.component"; import { StorageLink as StorageLink, AppStorage as AppStorage } from "@ohos.arkui.stateManagement"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts index 45b0eed2b1ccb9633469506eb853228b03dca2cf..dfed251b28cef5b1b176c9ba4ca20be176f11916 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts @@ -44,8 +44,6 @@ import { IStorageLinkDecoratedVariable as IStorageLinkDecoratedVariable } from " import { NavInterface as NavInterface } from "arkui.UserView"; import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent"; import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; import { StorageLink as StorageLink } from "@ohos.arkui.stateManagement"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts index 057ffec8607656cae6bae369f54ab48e693135e6..2b544b79425efc9ef6a6f09ede490c002b4f8bb0 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts @@ -44,8 +44,6 @@ import { IStorageLinkDecoratedVariable as IStorageLinkDecoratedVariable } from " import { NavInterface as NavInterface } from "arkui.UserView"; import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent"; import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; import { StorageLink as StorageLink } from "@ohos.arkui.stateManagement"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..60263a47116d7d3ecf0d42222eaaabde9fcd0f43 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts @@ -0,0 +1,281 @@ +/* + * 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 STORAGEPROP_DIR_PATH: string = 'decorators/storageprop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, STORAGEPROP_DIR_PATH, 'storageprop-ref-complex-type.ets'), +]; + +const storagePropTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed, +} + +const pluginTester = new PluginTester('test @StoragePropRef complex type transform', buildConfig); + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IStoragePropRefDecoratedVariable as IStoragePropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { StoragePropRef as StoragePropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + + + +class Person { + public name: string = ""; + + public constructor(name: string) {} + +} + +final class Status extends BaseEnum { + private readonly #ordinal: int; + + private static () {} + + public constructor(ordinal: int, value: int) { + super(value); + this.#ordinal = ordinal; + } + + public static readonly Success: Status = new Status(0, 200); + + public static readonly NotFound: Status = new Status(1, 404); + + public static readonly ServerError: Status = new Status(2, 500); + + private static readonly #NamesArray: String[] = ["Success", "NotFound", "ServerError"]; + + private static readonly #ValuesArray: int[] = [200, 404, 500]; + + private static readonly #StringValuesArray: String[] = ["200", "404", "500"]; + + private static readonly #ItemsArray: Status[] = [Status.Success, Status.NotFound, Status.ServerError]; + + public getName(): String { + return Status.#NamesArray[this.#ordinal]; + } + + public static getValueOf(name: String): Status { + for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + if (((name) == (Status.#NamesArray[i]))) { + return Status.#ItemsArray[i]; + } + } + throw new Error((("No enum constant Status.") + (name))); + } + + public static fromValue(value: int): Status { + for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + if (((value) == (Status.#ValuesArray[i]))) { + return Status.#ItemsArray[i]; + } + } + throw new Error((("No enum Status with value ") + (value))); + } + + public valueOf(): int { + return Status.#ValuesArray[this.#ordinal]; + } + + public toString(): String { + return Status.#StringValuesArray[this.#ordinal]; + } + + public static values(): Status[] { + return Status.#ItemsArray; + } + + public getOrdinal(): int { + return this.#ordinal; + } + + public static $_get(e: Status): String { + return e.getName(); + } + +} + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_arrayB = STATE_MGMT_FACTORY.makeStoragePropRef>(this, "Prop1", "arrayB", [1, 2, 3], Type.from>()) + this.__backing_objectB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop2", "objectB", {}, Type.from()) + this.__backing_dateB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop3", "dateB", new Date("2021-09-09"), Type.from()) + this.__backing_setB = STATE_MGMT_FACTORY.makeStoragePropRef>(this, "Prop4", "setB", new Set(), Type.from>()) + this.__backing_mapB = STATE_MGMT_FACTORY.makeStoragePropRef>(this, "Prop5", "mapB", new Map(), Type.from>()) + this.__backing_classB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop7", "classB", new Person("Kevin"), Type.from()) + this.__backing_enumB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop8", "enumB", Status.NotFound, Type.from()) + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_arrayB?: IStoragePropRefDecoratedVariable>; + + public get arrayB(): Array { + return this.__backing_arrayB!.get(); + } + + public set arrayB(value: Array) { + this.__backing_arrayB!.set(value); + } + + private __backing_objectB?: IStoragePropRefDecoratedVariable; + + public get objectB(): Object { + return this.__backing_objectB!.get(); + } + + public set objectB(value: Object) { + this.__backing_objectB!.set(value); + } + + private __backing_dateB?: IStoragePropRefDecoratedVariable; + + public get dateB(): Date { + return this.__backing_dateB!.get(); + } + + public set dateB(value: Date) { + this.__backing_dateB!.set(value); + } + + private __backing_setB?: IStoragePropRefDecoratedVariable>; + + public get setB(): Set { + return this.__backing_setB!.get(); + } + + public set setB(value: Set) { + this.__backing_setB!.set(value); + } + + private __backing_mapB?: IStoragePropRefDecoratedVariable>; + + public get mapB(): Map { + return this.__backing_mapB!.get(); + } + + public set mapB(value: Map) { + this.__backing_mapB!.set(value); + } + + private __backing_classB?: IStoragePropRefDecoratedVariable; + + public get classB(): Person { + return this.__backing_classB!.get(); + } + + public set classB(value: Person) { + this.__backing_classB!.set(value); + } + + private __backing_enumB?: IStoragePropRefDecoratedVariable; + + public get enumB(): Status { + return this.__backing_enumB!.get(); + } + + public set enumB(value: Status) { + this.__backing_enumB!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + set arrayB(arrayB: (Array | undefined)) + + get arrayB(): (Array | undefined) + set __backing_arrayB(__backing_arrayB: (IStoragePropRefDecoratedVariable> | undefined)) + + get __backing_arrayB(): (IStoragePropRefDecoratedVariable> | undefined) + set objectB(objectB: (Object | undefined)) + + get objectB(): (Object | undefined) + set __backing_objectB(__backing_objectB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_objectB(): (IStoragePropRefDecoratedVariable | undefined) + set dateB(dateB: (Date | undefined)) + + get dateB(): (Date | undefined) + set __backing_dateB(__backing_dateB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_dateB(): (IStoragePropRefDecoratedVariable | undefined) + set setB(setB: (Set | undefined)) + + get setB(): (Set | undefined) + set __backing_setB(__backing_setB: (IStoragePropRefDecoratedVariable> | undefined)) + + get __backing_setB(): (IStoragePropRefDecoratedVariable> | undefined) + set mapB(mapB: (Map | undefined)) + + get mapB(): (Map | undefined) + set __backing_mapB(__backing_mapB: (IStoragePropRefDecoratedVariable> | undefined)) + + get __backing_mapB(): (IStoragePropRefDecoratedVariable> | undefined) + set classB(classB: (Person | undefined)) + + get classB(): (Person | undefined) + set __backing_classB(__backing_classB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_classB(): (IStoragePropRefDecoratedVariable | undefined) + set enumB(enumB: (Status | undefined)) + + get enumB(): (Status | undefined) + set __backing_enumB(__backing_enumB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_enumB(): (IStoragePropRefDecoratedVariable | undefined) + +} +`; + +function testStoragePropTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @StoragePropRef complex type transform', + [storagePropTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testStoragePropTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbf9c9f85eeea69204863e136a745460b3a823c7 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts @@ -0,0 +1,172 @@ +/* + * 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 STORAGEPROP_DIR_PATH: string = 'decorators/storageprop-ref'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, STORAGEPROP_DIR_PATH, 'storageprop-ref-primitive-type.ets'), +]; + +const storagePropTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed, +} + +const pluginTester = new PluginTester('test @StoragePropRef primitive type transform', buildConfig); + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IStoragePropRefDecoratedVariable as IStoragePropRefDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Component as Component } from "@ohos.arkui.component"; + +import { StoragePropRef as StoragePropRef } from "@ohos.arkui.stateManagement"; + +function main() {} + + + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + this.__backing_numB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop1", "numB", 43, Type.from()) + this.__backing_stringB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop2", "stringB", "BB", Type.from()) + this.__backing_booleanB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop3", "booleanB", false, Type.from()) + this.__backing_undefinedB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop4", "undefinedB", undefined, Type.from()) + this.__backing_nullB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop5", "nullB", null, Type.from()) + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_numB?: IStoragePropRefDecoratedVariable; + + public get numB(): number { + return this.__backing_numB!.get(); + } + + public set numB(value: number) { + this.__backing_numB!.set(value); + } + + private __backing_stringB?: IStoragePropRefDecoratedVariable; + + public get stringB(): string { + return this.__backing_stringB!.get(); + } + + public set stringB(value: string) { + this.__backing_stringB!.set(value); + } + + private __backing_booleanB?: IStoragePropRefDecoratedVariable; + + public get booleanB(): boolean { + return this.__backing_booleanB!.get(); + } + + public set booleanB(value: boolean) { + this.__backing_booleanB!.set(value); + } + + private __backing_undefinedB?: IStoragePropRefDecoratedVariable; + + public get undefinedB(): undefined { + return this.__backing_undefinedB!.get(); + } + + public set undefinedB(value: undefined) { + this.__backing_undefinedB!.set(value); + } + + private __backing_nullB?: IStoragePropRefDecoratedVariable; + + public get nullB(): null { + return this.__backing_nullB!.get(); + } + + public set nullB(value: null) { + this.__backing_nullB!.set(value); + } + + @memo() public build() {} + + private constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + set numB(numB: (number | undefined)) + + get numB(): (number | undefined) + set __backing_numB(__backing_numB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_numB(): (IStoragePropRefDecoratedVariable | undefined) + set stringB(stringB: (string | undefined)) + + get stringB(): (string | undefined) + set __backing_stringB(__backing_stringB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_stringB(): (IStoragePropRefDecoratedVariable | undefined) + set booleanB(booleanB: (boolean | undefined)) + + get booleanB(): (boolean | undefined) + set __backing_booleanB(__backing_booleanB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_booleanB(): (IStoragePropRefDecoratedVariable | undefined) + set undefinedB(undefinedB: (undefined | undefined)) + + get undefinedB(): (undefined | undefined) + set __backing_undefinedB(__backing_undefinedB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_undefinedB(): (IStoragePropRefDecoratedVariable | undefined) + set nullB(nullB: (null | undefined)) + + get nullB(): (null | undefined) + set __backing_nullB(__backing_nullB: (IStoragePropRefDecoratedVariable | undefined)) + + get __backing_nullB(): (IStoragePropRefDecoratedVariable | undefined) + +} +`; + +function testStoragePropTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @StoragePropRef primitive type transform', + [storagePropTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testStoragePropTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts index cbd0b0844779a8d64073f95dc1899f5b045a754a..6c3476c961be22ae5c6c00aaefdcb7ac82c1061c 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts @@ -52,9 +52,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts index c5d5cf897271ad9d5c656f42b857dc2f75e9a8d7..e03a903c563bad0cb4dac9b0bdd5399d11ff1663 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts @@ -44,8 +44,6 @@ import { IStoragePropRefDecoratedVariable as IStoragePropRefDecoratedVariable } import { NavInterface as NavInterface } from "arkui.UserView"; import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent"; import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; import { StorageProp as StorageProp } from "@ohos.arkui.stateManagement"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts index 03d383f07733f2d23d9b902080fcacbfefab8b58..25ed76fdea8263d1492181d2d8f3c136fb03a0a0 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts @@ -50,9 +50,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts index 9857c430b120911c767beab00edac722431433c1..ecff9abbcd80ca5e2c26d3db5644619b3330f7ab 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts @@ -78,9 +78,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts index 74d90e24922360f2d60d18824b28ddceb37994a4..216eb90861f4128ac63bcdff4ae070e5f258c70e 100644 --- a/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts @@ -54,10 +54,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Text as Text, Entry as Entry, Column as Column, Component as Component, $$ as $$, Grid as Grid, GridItem as GridItem } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts index 2545064bca000b9e8036cd0b3f7f6bb7fd6961a1..98c87cc963629c031250d58de4dfa6f8763f0f36 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts index 23b0c1164a265525f71d177c5a9f011e952f3723..23daf7f6fcc7c94608010ae6903dbeb634719710 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts @@ -44,9 +44,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts index 7f312d799738ad4d1d8a90f14bac0b3ba7c10042..35a3172891994d681037ca83c06d9b8df290b106 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts @@ -44,9 +44,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts index 6c62d8b25e481b2a7c6aa6aa9245e097cda736dc..54549712e7ed07404a22bd4910c2bd572329d4c6 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts index 76cd2c907446f944cfa7046add3f65fd3efa9d2f..0a75f6608b73e0834801c2409b427d82b2680f22 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts index 363159cc64cb879b38ae54e6d4ffd33d965b3814..523129df9e182a4fe4bafb0052fb379b12c7c973 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts index 367564302df027ae0a198301fa8a3c751558f833..104404f1c3e3d2399327b3fce08032315f2e0fc9 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts b/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts index 466feecd263b23b93d835d8ad318d093f518f992..9d0ee82400a48ff4ad872d92c2cf321f02093927 100644 --- a/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts @@ -45,9 +45,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; diff --git a/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts b/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts index dc71b2bd38dd8f8738bd020bc1aa912cc1c03ab1..79e3668c532a79af6de4af9d53ea0f3508f9979c 100644 --- a/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts @@ -40,11 +40,6 @@ const importParsed: Plugins = { const pluginTester = new PluginTester('test import transform', buildConfig); const expectedParsedScript: string = ` - -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text } from "@ohos.arkui.component"; @@ -72,13 +67,8 @@ import { SimpleStruct as SimpleStruct } from "./utils/simple-struct"; `; const expectedCheckedScript: string = ` - import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text } from "@ohos.arkui.component"; diff --git a/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts b/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts index 53bb01be8d98fcdb61429fae034b76a6f55881e0..0147ea48f9ced29fa9f9c1545289e25634dedd6c 100644 --- a/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts @@ -44,10 +44,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Prop as Prop, Column as Column, Entry as Entry } from "@kit.ArkUI"; @@ -121,10 +117,6 @@ import { PageLifeCycle as PageLifeCycle } from "arkui.component.customComponent" import { EntryPoint as EntryPoint } from "arkui.UserView"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Prop as Prop, Column as Column, Entry as Entry } from "@kit.ArkUI"; diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts index b88e465bd50c76f361cacdb49b8baa89fc825673..c3443baebc981a5bdd94c81d55d5e2b17df311b1 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts @@ -40,8 +40,6 @@ const parsedTransform: Plugins = { const expectedUIScript: string = ` import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Builder as Builder, Column as Column } from "@kit.ArkUI"; @@ -92,10 +90,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Builder as Builder, Column as Column } from "@kit.ArkUI"; 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 42bb161d17100424a3e0dbfca01bd02e8ac88537..0b6a8c4ebef6d279b560c4b4b6b64df244ba7d49 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 @@ -42,10 +42,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Builder as Builder, Column as Column, ForEach as ForEach } from "@kit.ArkUI"; @@ -111,10 +107,6 @@ import { memo as memo } from "arkui.stateManagement.runtime"; import { TextAttribute as TextAttribute } from "arkui.component.text"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Text as Text, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Builder as Builder, Column as Column, ForEach as ForEach } from "@kit.ArkUI"; diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts index caa6e8154b579a1a1d1551c133bb8b15b241d591..38ef976e6db101c0c27258bd8a3de3cd83ea166f 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts @@ -59,10 +59,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Observed as Observed, Builder as Builder, Entry as Entry, Component as Component, State as State } from "@kit.ArkUI"; @@ -210,10 +206,6 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { memo as memo } from "arkui.stateManagement.runtime"; -import { LayoutCallback as LayoutCallback } from "arkui.component.customComponent"; - -import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; - import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Observed as Observed, Builder as Builder, Entry as Entry, Component as Component, State as State } from "@kit.ArkUI"; diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index 0dbc8b4458dfb19a07dc4ca473510db86443c33a..d5efa568a48aa7ec32eb22f29fcecf461b1ddbab 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -24,7 +24,6 @@ import { isEntryWrapperClass } from './entry-translators/utils'; import { ImportCollector } from '../common/import-collector'; import { DeclarationCollector } from '../common/declaration-collector'; import { PropertyCache } from './property-translators/utils'; -import { checkCustomDialogController, insertImportDeclaration, transformDeclaration } from './customdialog'; import { LogCollector } from '../common/log-collector'; import { CustomComponentScopeInfo, @@ -35,7 +34,13 @@ import { ScopeInfoCollection, isForEachDecl } from './struct-translators/utils'; -import { collectCustomComponentScopeInfo, CustomComponentNames, isCustomComponentClass } from './utils'; +import { + collectCustomComponentScopeInfo, + CustomComponentNames, + CustomDialogNames, + isCustomComponentClass, + isSpecificNewClass, +} from './utils'; import { findAndCollectMemoableNode } from '../collectors/memo-collectors/factory'; export class CheckedTransformer extends AbstractVisitor { @@ -87,24 +92,6 @@ export class CheckedTransformer extends AbstractVisitor { } } - isCustomDialogController(): boolean { - if (this.isExternal && this.externalSourceName === 'arkui.component.customDialogController') { - return true; - } - return false; - } - - processCustomDialogController(node: arkts.AstNode): arkts.AstNode { - if (arkts.isEtsScript(node)) { - insertImportDeclaration(this.program); - } - if (arkts.isClassDeclaration(node) && node.definition && node.definition.ident && - node.definition.ident.name === 'CustomDialogController') { - return transformDeclaration(node as arkts.ClassDeclaration); - } - return node; - } - visitor(beforeChildren: arkts.AstNode): arkts.AstNode { this.enter(beforeChildren); if (arkts.isCallExpression(beforeChildren) && isBuilderLambda(beforeChildren)) { @@ -119,9 +106,7 @@ export class CheckedTransformer extends AbstractVisitor { } const node = this.visitEachChild(beforeChildren); findAndCollectMemoableNode(node); - if (this.isCustomDialogController()) { - return this.processCustomDialogController(node); - } else if ( + if ( arkts.isClassDeclaration(node) && this.scope.customComponents.length > 0 && isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) @@ -141,8 +126,8 @@ export class CheckedTransformer extends AbstractVisitor { return structFactory.AddArrowTypeForParameter(node); } else if (arkts.isTSInterfaceDeclaration(node)) { return structFactory.tranformInterfaceMembers(node, this.externalSourceName); - } else if (arkts.isBlockStatement(node)) { - return checkCustomDialogController(node); + } else if (arkts.isETSNewClassInstanceExpression(node) && isSpecificNewClass(node, CustomDialogNames.CUSTOM_DIALOG_CONTROLLER)) { + return structFactory.transformCustomDialogController(node); } if (arkts.isEtsScript(node) && ImportCollector.getInstance().importInfos.length > 0) { ImportCollector.getInstance().insertCurrentImports(this.program); diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index 8d9c5aaf41c0fcb5d391b2acd908fd664a5479e9..83661d6876a8d2d26568e1492f0f598f9943bdf3 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -25,6 +25,9 @@ import { CustomComponentInfo, collectCustomComponentScopeInfo, isComponentStruct, + isCustomDialogControllerOptions, + getComponentExtendsName, + ComponentType, } from './utils'; import { backingField, @@ -52,7 +55,6 @@ import { EntryWrapperNames, } from '../common/predefines'; import { generateInstantiateInterop } from './interop/interop'; -import { createCustomDialogMethod, isNewCustomDialogController, transformController } from './customdialog'; export interface ComponentTransformerOptions extends VisitorOptions { arkui?: string; @@ -76,6 +78,7 @@ export class ComponentTransformer extends AbstractVisitor { private structMembersMap: Map = new Map(); private isCustomComponentImported: boolean = false; private isCustomComponentV2Imported: boolean = false; + private isBaseCustomDialogImported: boolean = false; private isEntryPointImported: boolean = false; private isPageLifeCycleImported: boolean = false; private isLayoutCallbackImported: boolean = false; @@ -83,9 +86,14 @@ export class ComponentTransformer extends AbstractVisitor { private hasLegacy: boolean = false; private legacyStructMap: Map = new Map(); private legacyCallMap: Map = new Map(); - private customDialogController: string = ''; private projectConfig: ProjectConfig | undefined; private entryRouteName: string | undefined; + private componentType: ComponentType = { + hasComponent: false, + hasComponentV2: false, + hasCustomDialog: false, + hasCustomLayout: false, + }; constructor(options?: ComponentTransformerOptions) { const _options: ComponentTransformerOptions = options ?? {}; @@ -101,6 +109,7 @@ export class ComponentTransformer extends AbstractVisitor { this.structMembersMap = new Map(); this.isCustomComponentImported = false; this.isCustomComponentV2Imported = false; + this.isBaseCustomDialogImported = false; this.isEntryPointImported = false; this.isPageLifeCycleImported = false; this.isLayoutCallbackImported = false; @@ -108,7 +117,12 @@ export class ComponentTransformer extends AbstractVisitor { this.hasLegacy = false; this.legacyStructMap = new Map(); this.legacyCallMap = new Map(); - this.customDialogController = ''; + this.componentType = { + hasComponent: false, + hasComponentV2: false, + hasCustomDialog: false, + hasCustomLayout: false, + }; } enter(node: arkts.AstNode) { @@ -132,6 +146,13 @@ export class ComponentTransformer extends AbstractVisitor { CustomComponentNames.COMPONENT_V2_CLASS_NAME ); } + if (arkts.isETSImportDeclaration(node) && !this.isBaseCustomDialogImported) { + this.isBaseCustomDialogImported = !!findLocalImport( + node, + CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, + CustomComponentNames.BASE_CUSTOM_DIALOG_NAME + ); + } if (arkts.isETSImportDeclaration(node) && !this.isEntryPointImported) { this.isEntryPointImported = !!findLocalImport( node, @@ -153,9 +174,6 @@ export class ComponentTransformer extends AbstractVisitor { CustomComponentNames.LAYOUT_CALLBACK ); } - if (this.isCustomDialog() && arkts.isClassProperty(node)) { - this.hasCustomDialogController(node); - } } exit(node: arkts.AstNode) { @@ -167,38 +185,6 @@ export class ComponentTransformer extends AbstractVisitor { } } - isCustomDialog(): boolean { - if (this.scopeInfos.length === 0) { - return false; - } - const scopeInfo: ScopeInfo = this.scopeInfos[this.scopeInfos.length - 1]; - return !!scopeInfo.annotations.customdialog; - } - - hasController(node: arkts.ETSTypeReference, key_name: string): void { - const ident = node.part?.name; - if (ident && arkts.isIdentifier(ident) && ident.name === 'CustomDialogController') { - this.customDialogController = key_name; - } - } - - hasCustomDialogController(node: arkts.ClassProperty): void { - const key = node.key; - if (!(key && arkts.isIdentifier(key) && node.typeAnnotation)) { - return; - } - const typeAnno = node.typeAnnotation; - if (arkts.isETSUnionType(typeAnno)) { - for (const type of typeAnno.types) { - if (arkts.isETSTypeReference(type)) { - this.hasController(type, key.name); - } - } - } else if (arkts.isETSTypeReference(typeAnno)) { - this.hasController(typeAnno, key.name); - } - } - createImportDeclaration(sourceName: string, importedName: string): void { const source: arkts.StringLiteral = arkts.factory.create1StringLiteral(sourceName); const imported: arkts.Identifier = arkts.factory.createIdentifier(importedName); @@ -230,18 +216,7 @@ export class ComponentTransformer extends AbstractVisitor { updateStatements.push(factory.createIntrinsicAnnotationDeclaration({ expr })); } if (this.componentInterfaceCollection.length > 0) { - if (!this.isCustomComponentImported) - this.createImportDeclaration( - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.COMPONENT_CLASS_NAME - ); - if (!this.isCustomComponentV2Imported) - this.createImportDeclaration( - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.COMPONENT_V2_CLASS_NAME - ); - if (!this.isLayoutCallbackImported) - this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.LAYOUT_CALLBACK); + this.insertComponentImport(); updateStatements.push(...this.componentInterfaceCollection); } @@ -253,11 +228,7 @@ export class ComponentTransformer extends AbstractVisitor { this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.PAGE_LIFE_CYCLE); updateStatements.push(...this.entryNames.map(entryFactory.generateEntryWrapper)); updateStatements.push( - entryFactory.callRegisterNamedRouter( - this.entryRouteName, - this.projectConfig, - this.program?.absName - ) + entryFactory.callRegisterNamedRouter(this.entryRouteName, this.projectConfig, this.program?.absName) ); this.createImportDeclaration(ENTRY_POINT_IMPORT_SOURCE_NAME, NavigationNames.NAVINTERFACE); } @@ -267,6 +238,30 @@ export class ComponentTransformer extends AbstractVisitor { return node; } + insertComponentImport(): void { + if (!this.isCustomComponentImported && this.componentType.hasComponent) { + this.createImportDeclaration( + CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, + CustomComponentNames.COMPONENT_CLASS_NAME + ); + } + if (!this.isCustomComponentV2Imported && this.componentType.hasComponentV2) { + this.createImportDeclaration( + CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, + CustomComponentNames.COMPONENT_V2_CLASS_NAME + ); + } + if (!this.isBaseCustomDialogImported && this.componentType.hasCustomDialog) { + this.createImportDeclaration( + CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, + CustomComponentNames.BASE_CUSTOM_DIALOG_NAME + ); + } + if (!this.isLayoutCallbackImported && this.componentType.hasCustomLayout) { + this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.LAYOUT_CALLBACK); + } + } + updateEntryPoint(node: arkts.ClassDeclaration): arkts.ClassDeclaration { if (!node.definition) { return node; @@ -349,11 +344,6 @@ export class ComponentTransformer extends AbstractVisitor { this.entryRouteName = routeName.value.str; } } - if (!!scopeInfo.annotations.customdialog) { - const setDialogController = createCustomDialogMethod(this.customDialogController); - newDefinitionBody.push(setDialogController); - this.customDialogController = ''; - } const newDefinition: arkts.ClassDefinition = this.createNewDefinition( node, className, @@ -390,9 +380,7 @@ export class ComponentTransformer extends AbstractVisitor { } } const scopeInfo = this.scopeInfos[this.scopeInfos.length - 1]; - const extendsName: string = scopeInfo.annotations.component - ? CustomComponentNames.COMPONENT_CLASS_NAME - : CustomComponentNames.COMPONENT_V2_CLASS_NAME; + const extendsName: string = getComponentExtendsName(scopeInfo.annotations, this.componentType); return arkts.factory .createClassDefinition( definition.ident, @@ -538,9 +526,6 @@ export class ComponentTransformer extends AbstractVisitor { if (arkts.isEtsScript(newNode)) { return this.processEtsScript(newNode); } - if (isNewCustomDialogController(newNode)) { - return transformController(newNode as arkts.ETSNewClassInstanceExpression); - } if ( arkts.isStructDeclaration(newNode) && this.scopeInfos.length > 0 && @@ -557,6 +542,12 @@ export class ComponentTransformer extends AbstractVisitor { ) { return this.updateEntryPoint(newNode); } + if ( + arkts.isTSInterfaceDeclaration(newNode) && + isCustomDialogControllerOptions(newNode, this.externalSourceName) + ) { + return factory.updateCustomDialogOptionsInterface(newNode); + } // process interop code if (!this.hasLegacy) { return newNode; diff --git a/arkui-plugins/ui-plugins/customdialog.ts b/arkui-plugins/ui-plugins/customdialog.ts deleted file mode 100644 index 8a238ab053c2c1e80b9fb0eab0e7599cacb46ea2..0000000000000000000000000000000000000000 --- a/arkui-plugins/ui-plugins/customdialog.ts +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 2022-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 { factory } from './ui-factory'; -import { - CustomComponentNames, - getCustomComponentOptionsName, -} from './utils'; -import { stat } from 'fs'; -import { createAndInsertImportDeclaration } from '../common/arkts-utils'; - -export function createCustomDialogMethod(controller: string): arkts.MethodDefinition { - const param: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( - arkts.factory.createIdentifier( - 'controller', - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(CustomComponentNames.CUSTOMDIALOG_CONTROLLER) - ) - ) - ), - undefined - ); - - const block = arkts.factory.createBlock( - (controller.length !== 0) ? [ - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(controller), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - arkts.factory.createIdentifier('controller') - ) - ) - ] : [] - ); - - const script = arkts.factory.createScriptFunction( - block, - arkts.FunctionSignature.createFunctionSignature( - undefined, - [param], - arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), - false - ), - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC - ); - - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, - arkts.factory.createIdentifier(CustomComponentNames.SETDIALOGCONTROLLER_METHOD), - script, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - false - ); -} - -export function transformCallToArrow(value: arkts.CallExpression): arkts.ArrowFunctionExpression { - const className = value.expression.name; - const args = value.arguments; - const as_value = arkts.factory.createExpressionStatement( - arkts.factory.updateCallExpression( - value, - value.expression, - value.typeArguments, - args.length === 0 ? [] : [ - arkts.factory.createTSAsExpression( - args[0], - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(getCustomComponentOptionsName(className)) - ) - ), - false - ) - ] - ) - ); - const newValue = arkts.factory.createArrowFunction( - factory.createScriptFunction( - { - body: arkts.factory.createBlock([as_value]), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - } - ) - ); - return newValue; -} - -export function transformController(newInstance: arkts.ETSNewClassInstanceExpression): arkts.ETSNewClassInstanceExpression { - const arg = newInstance.getArguments[0]; - if (!arkts.isObjectExpression(arg)) { - throw new Error('Error CustomDialogOptions'); - } - const properties = arg.properties as arkts.Property[]; - const property = properties[0]; - const value = property?.value; - if (!(value && arkts.isCallExpression(value) && arkts.isIdentifier(value.expression))) { - return newInstance; - } - - const memoArrow = transformCallToArrow(value); - properties[0] = arkts.Property.updateProperty( - property, - property.key, - memoArrow - ); - const newObj = arkts.ObjectExpression.updateObjectExpression( - arg, - arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, - properties, - false - ); - const asOptions = arkts.factory.createTSAsExpression( - newObj, - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(CustomComponentNames.CUSTOMDIALOG_CONTROLLER_OPTIONS) - ) - ), - false - ); - return arkts.factory.updateETSNewClassInstanceExpression( - newInstance, - newInstance.getTypeRef, - [asOptions] - ); -} - -function createVarExpression(key_name: string, isProperty: boolean): arkts.Expression { - if (!isProperty) { - return arkts.factory.createIdentifier(key_name + '_Temp'); - } - return arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(key_name), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); -} - -function createInvoke(key_name: string, isProperty: boolean): arkts.AstNode[] { - const statements: arkts.AstNode[] = []; - const varExpression = createVarExpression(key_name, isProperty); - if (!isProperty) { - const createVar = arkts.factory.createVariableDeclaration( - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST, - [ - arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_CONST, - arkts.factory.createIdentifier((varExpression as arkts.Identifier).name), - arkts.factory.createIdentifier(key_name) - ) - ] - ); - statements.push(createVar); - } - const invoke = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - arkts.factory.createIdentifier('newInstance'), - arkts.factory.createIdentifier(CustomComponentNames.SETDIALOGCONTROLLER_METHOD), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - undefined, - [ - arkts.factory.createTSAsExpression( - varExpression, - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(CustomComponentNames.CUSTOMDIALOG_CONTROLLER) - ) - ), - false - ) - ] - ) - ); - statements.push(invoke); - return statements; -} - -function updateStyleBlock(key_name: string, dialogName: string, isProperty: boolean): arkts.BlockStatement { - const invokeSetController = createInvoke(key_name, isProperty); - return arkts.factory.createBlock( - [ - arkts.factory.createVariableDeclaration( - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, - [ - arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, - arkts.factory.createIdentifier('newInstance'), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(dialogName)) - ), - [] - ) - ) - ] - ), - ...invokeSetController, - arkts.factory.createReturnStatement( - arkts.factory.createIdentifier('newInstance') - ) - ] - ); -} - -function updateStyle(style: arkts.ArrowFunctionExpression, key_name: string, dialogName: string, isProperty: boolean): arkts.ArrowFunctionExpression { - const block = updateStyleBlock(key_name, dialogName, isProperty); - return arkts.factory.updateArrowFunction( - style, - factory.createScriptFunction( - { - body: block, - returnTypeAnnotation: arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(dialogName) - ) - ), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE - } - ) - ); -} - -export function updateArrow(arrow: arkts.ArrowFunctionExpression, controller: string, isProperty: boolean): arkts.ArrowFunctionExpression { - const scriptFunction = arrow.scriptFunction as arkts.ScriptFunction; - const statement = scriptFunction.body!.statements[0] as arkts.ExpressionStatement; - const call = statement.expression as arkts.CallExpression; - const member = call.expression as arkts.MemberExpression; - - const dialogName = member.object.name; - const styleArrow = call.arguments[1] as arkts.ArrowFunctionExpression; - const newStyle = updateStyle(styleArrow, controller, dialogName, isProperty); - const newScriptFunction = factory.createScriptFunction( - { - body: arkts.factory.createBlock([ - arkts.factory.createExpressionStatement( - arkts.factory.updateCallExpression( - call, - member, - call.typeArguments, - [ - call.arguments[0], - newStyle, - ...call.arguments.slice(2) - ] - ) - ) - ]), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE - } - ); - const newArrow = arkts.factory.updateArrowFunction( - arrow, - newScriptFunction - ); - return newArrow; -} - -export function updateCtor(ctor: arkts.MethodDefinition): arkts.MethodDefinition { - const script = ctor.scriptFunction; - const newScriptFunction = arkts.factory.createScriptFunction( - script.body, - arkts.factory.createFunctionSignature( - undefined, - [ - ...script.params, - arkts.factory.createParameterDeclaration( - arkts.factory.createIdentifier( - 'component', - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('ExtendableComponent') - ) - ) - ), - undefined - ) - ], - undefined, - false - ), - script.flags, - script.modifiers - ); - const newCtor = arkts.factory.updateMethodDefinition( - ctor, - ctor.kind, - arkts.factory.createIdentifier(ctor.name.name), - newScriptFunction, - ctor.modifiers, - false - ); - return newCtor; -} - -export function updateBody(body: arkts.Statement[]): arkts.Statement[] { - let result: arkts.Statement[] = []; - for (const statement of body) { - if (arkts.isMethodDefinition(statement) && statement.name.name === 'constructor') { - const ctor = updateCtor(statement); - result.push(ctor); - } else { - result.push(statement); - } - } - return result; -} - - -export function insertImportDeclaration(program: arkts.Program | undefined): void { - if (!program) { - throw Error('Failed to insert import: Transformer has no program'); - } - const imported = arkts.factory.createIdentifier('ExtendableComponent'); - createAndInsertImportDeclaration( - arkts.factory.createStringLiteral('./extendableComponent'), - imported, - imported, - arkts.Es2pandaImportKinds.IMPORT_KINDS_VALUE, - program - ); -} - -export function transformDeclaration(node: arkts.ClassDeclaration): arkts.ClassDeclaration { - const definition = node.definition!; - const newBody = updateBody(definition.body as arkts.Statement[]); - const newDefinition = arkts.factory.updateClassDefinition( - definition, - definition?.ident, - undefined, - definition.superTypeParams, - definition.implements, - undefined, - definition.super, - newBody, - definition.modifiers, - arkts.classDefinitionFlags(definition) - ); - const declaration = arkts.factory.updateClassDeclaration( - node, - newDefinition - ); - return declaration; -} - -export function updateNewClassInstanceExpression(node: arkts.ETSNewClassInstanceExpression, varName: string, - isProperty: boolean): arkts.ETSNewClassInstanceExpression { - const asExression = node.getArguments[0] as arkts.TSAsExpression; - const arg = asExression.expr as arkts.ObjectExpression; - if (!arkts.isObjectExpression(arg)) { - throw new Error('Error CustomDialogOptions'); - } - const properties = arg.properties as arkts.Property[]; - const builder = properties[0]; - const builder_value = builder.value as arkts.ArrowFunctionExpression; - const newBuilderValue = updateArrow(builder_value, varName, isProperty); - const newProperty = arkts.factory.updateProperty( - builder, - builder.key, - newBuilderValue - ); - const newObj = arkts.factory.updateObjectExpression( - arg, - arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, - [newProperty, ...properties.slice(1)], - false - ); - const newAsExpression = arkts.factory.updateTSAsExpression( - asExression, - newObj, - asExression.typeAnnotation, - asExression.isConst - ); - const typeRef = node.getTypeRef as arkts.ETSTypeReference; - const newNode = arkts.factory.updateETSNewClassInstanceExpression( - node, - typeRef, - [newAsExpression, arkts.factory.createThisExpression()] - ); - return newNode; -} - -export function isNewCustomDialogController(node: arkts.AstNode | undefined): boolean { - if (node && arkts.isETSNewClassInstanceExpression(node) && - node.getTypeRef?.part?.name.name === 'CustomDialogController') { - return true; - } - return false; -} - -function updateVar(node: arkts.VariableDeclarator): arkts.VariableDeclarator { - if (node.flag !== arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET) { - throw Error('Error VariableDeclarator CustomDialogController'); - } - return arkts.factory.updateVariableDeclarator( - node, - node.flag, - node.name, - arkts.factory.createUndefinedLiteral() - ); -} - -export function checkCustomDialogController(node: arkts.BlockStatement): arkts.BlockStatement { - const statements = node.statements; - const newStatements: arkts.AstNode[] = []; - for (let i = 0; i < statements.length; i++) { - const statement = statements[i]; - if (arkts.isVariableDeclaration(statement) && statement.declarators.length > 0 && - isNewCustomDialogController(statement.declarators[0].initializer)) { - const varDeclare = statement.declarators[0]; - const varName = varDeclare.name.name; - const classInstance = varDeclare.initializer; - const newClass = updateNewClassInstanceExpression(classInstance as arkts.ETSNewClassInstanceExpression, varName, false); - const newVar = arkts.factory.updateVariableDeclaration( - statement, - 0, - statement.declarationKind, - [updateVar(statement.declarators[0])] - ); - newStatements.push(newVar); - const initVar = arkts.factory.createAssignmentExpression( - arkts.factory.createIdentifier(varName), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - newClass - ); - const initStatement = arkts.factory.createExpressionStatement(initVar); - newStatements.push(initStatement); - } else { - newStatements.push(statement); - } - } - return arkts.factory.updateBlock( - node, - newStatements - ); - -} \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/property-translators/factory.ts b/arkui-plugins/ui-plugins/property-translators/factory.ts index c6bc8e859e99a776b0384e07e9d4685c5c3a3aea..1843bc77a44c42f5e4fa0a7fc1949d5c417c6a12 100644 --- a/arkui-plugins/ui-plugins/property-translators/factory.ts +++ b/arkui-plugins/ui-plugins/property-translators/factory.ts @@ -17,7 +17,7 @@ import * as arkts from '@koalaui/libarkts'; import { GenSymGenerator } from '../../common/gensym-generator'; import { DecoratorNames, DECORATOR_TYPE_MAP, StateManagementTypes } from '../../common/predefines'; import { factory as UIFactory } from '../ui-factory'; -import { collectStateManagementTypeImport, getValueInAnnotation, hasDecorator, removeDecorator } from './utils'; +import { collectStateManagementTypeImport, getValueInAnnotation, hasDecorator, removeDecorator, generateThisBacking } from './utils'; import { CustomComponentNames } from '../utils'; import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../../collectors/memo-collectors/utils'; import { annotation } from '../../common/arkts-utils'; @@ -172,7 +172,7 @@ export class factory { false, [ arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(factory.generateThisCall(callbackName), undefined, [ + arkts.factory.createCallExpression(generateThisBacking(callbackName), undefined, [ arkts.factory.createIdentifier('_'), ]) ), @@ -180,20 +180,6 @@ export class factory { ); } - /* - * create this. with optional or nonNullable. - */ - static generateThisCall(name: string, optional: boolean = false, nonNull: boolean = false): arkts.Expression { - const member: arkts.Expression = arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(`${name}`), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - optional - ); - return nonNull ? arkts.factory.createTSNonNullExpression(member) : member; - } - /* * create `initializers!.!.()`. */ diff --git a/arkui-plugins/ui-plugins/property-translators/index.ts b/arkui-plugins/ui-plugins/property-translators/index.ts index aa0c767c5c50ed37625b3c6ac642f0782a8ce797..133d35329776f65b806b408d703cfea026117a22 100644 --- a/arkui-plugins/ui-plugins/property-translators/index.ts +++ b/arkui-plugins/ui-plugins/property-translators/index.ts @@ -32,8 +32,12 @@ import { StoragePropInterfaceTranslator, StoragePropTranslator } from './storage import { ConsumeInterfaceTranslator, ConsumeTranslator } from './consume'; import { ProvideInterfaceTranslator, ProvideTranslator } from './provide'; import { BuilderParamInterfaceTranslator, BuilderParamTranslator } from './builderParam'; +import { PropRefInterfaceTranslator, PropRefTranslator } from './propRef'; import { ObservedTrackTranslator } from './observedTrack'; import { ClassScopeInfo } from './types'; +import { LocalInterfaceTranslator, LocalTranslator } from './local'; +import { StoragePropRefInterfaceTranslator, StoragePropRefTranslator } from './storagePropRef'; +import { LocalStoragePropRefInterfaceTranslator, LocalStoragePropRefTranslator } from './localStoragePropRef'; export { PropertyTranslator, InterfacePropertyTranslator }; export type { ClassScopeInfo }; @@ -63,12 +67,21 @@ export function classifyProperty( if (hasDecorator(property, DecoratorNames.LOCAL_STORAGE_PROP)) { return new LocalStoragePropTranslator({ property, structInfo }); } + if (hasDecorator(property, DecoratorNames.LOCAL_STORAGE_PROP_REF)) { + return new LocalStoragePropRefTranslator({ property, structInfo }); + } if (hasDecorator(property, DecoratorNames.STORAGE_PROP)) { return new StoragePropTranslator({ property, structInfo }); } + if (hasDecorator(property, DecoratorNames.STORAGE_PROP_REF)) { + return new StoragePropRefTranslator({ property, structInfo }); + } if (hasDecorator(property, DecoratorNames.PROP)) { return new PropTranslator({ property, structInfo }); } + if (hasDecorator(property, DecoratorNames.PROP_REF)) { + return new PropRefTranslator({ property, structInfo }); + } if (hasDecorator(property, DecoratorNames.PROVIDE)) { return new ProvideTranslator({ property, structInfo }); } @@ -92,6 +105,9 @@ export function classifyPropertyInInterface(property: arkts.AstNode): InterfaceP if (PropInterfaceTranslator.canBeTranslated(property)) { return new PropInterfaceTranslator({ property }); } + if (PropRefInterfaceTranslator.canBeTranslated(property)) { + return new PropRefInterfaceTranslator({ property }); + } if (ProvideInterfaceTranslator.canBeTranslated(property)) { return new ProvideInterfaceTranslator({ property }); } @@ -104,6 +120,12 @@ export function classifyPropertyInInterface(property: arkts.AstNode): InterfaceP if (StorageLinkInterfaceTranslator.canBeTranslated(property)) { return new StorageLinkInterfaceTranslator({ property }); } + if (StoragePropRefInterfaceTranslator.canBeTranslated(property)) { + return new StoragePropRefInterfaceTranslator({ property }); + } + if (LocalStoragePropRefInterfaceTranslator.canBeTranslated(property)) { + return new LocalStoragePropRefInterfaceTranslator({ property }); + } if (BuilderParamInterfaceTranslator.canBeTranslated(property)) { return new BuilderParamInterfaceTranslator({ property }); } diff --git a/arkui-plugins/ui-plugins/property-translators/local.ts b/arkui-plugins/ui-plugins/property-translators/local.ts new file mode 100644 index 0000000000000000000000000000000000000000..e61a06d257e531c064a04d60c0e5e35180dae83e --- /dev/null +++ b/arkui-plugins/ui-plugins/property-translators/local.ts @@ -0,0 +1,153 @@ +/* + * 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 { backingField, expectName } from '../../common/arkts-utils'; +import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { + generateToRecord, + createGetter, + createSetter2, + generateThisBacking, + generateGetOrSetCall, + hasDecorator, + collectStateManagementTypeImport, + PropertyCache, +} from './utils'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; +import { GetterSetter, InitializerConstructor } from './types'; +import { factory } from './factory'; + +export class LocalTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { + translateMember(): arkts.AstNode[] { + const originalName: string = expectName(this.property.key); + const newName: string = backingField(originalName); + this.cacheTranslatedInitializer(newName, originalName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string, originalName: string): void { + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { + const toRecord = generateToRecord(newName, originalName); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); + } + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field: arkts.ClassProperty = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.LOCAL_DECORATED, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisGet + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisSet + ); + + return [field, getter, setter]; + } + + translateGetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + returnValue: arkts.Expression + ): arkts.MethodDefinition { + return createGetter(originalName, typeAnnotation, returnValue); + } + + translateSetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + statement: arkts.AstNode + ): arkts.MethodDefinition { + return createSetter2(originalName, typeAnnotation, statement); + } + + generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { + const args: arkts.Expression[] = [ + arkts.factory.create1StringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + collectStateManagementTypeImport(StateManagementTypes.LOCAL_DECORATED); + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + factory.generateStateMgmtFactoryCall( + StateManagementTypes.MAKE_LOCAL, + this.property.typeAnnotation, + args, + true + ) + ); + return arkts.factory.createExpressionStatement(assign); + } +} + +export class LocalInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `ILocalDecoratedVariable | undefined`. + * + * @param method expecting getter with `@Local` and a setter with `@Local` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `ILocalDecoratedVariable | undefined`. + * + * @param property expecting property with `@Local`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts b/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..26053062dc7a07b9e4bb62da10a0aae2a205baf6 --- /dev/null +++ b/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts @@ -0,0 +1,166 @@ +/* + * 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 { backingField, expectName } from '../../common/arkts-utils'; +import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; +import { GetterSetter, InitializerConstructor } from './types'; +import { + generateToRecord, + createGetter, + createSetter2, + generateThisBacking, + generateGetOrSetCall, + collectStateManagementTypeImport, + hasDecorator, + PropertyCache, + getValueInAnnotation, +} from './utils'; +import { factory } from './factory'; + +export class LocalStoragePropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { + translateMember(): arkts.AstNode[] { + const originalName: string = expectName(this.property.key); + const newName: string = backingField(originalName); + + this.cacheTranslatedInitializer(newName, originalName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string, originalName: string): void { + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { + const toRecord = generateToRecord(newName, originalName); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); + } + } + + generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { + const localStoragePropRefValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.LOCAL_STORAGE_PROP_REF + ); + if (!localStoragePropRefValueStr) { + throw new Error('LocalStoragePropRef required only one value!!'); + } + + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(localStoragePropRefValueStr), + arkts.factory.create1StringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + factory.createTypeFrom(this.property.typeAnnotation), + ]; + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeImport(StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED); + return arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + factory.generateStateMgmtFactoryCall( + StateManagementTypes.MAKE_LOCAL_STORAGE_PROP_REF, + this.property.typeAnnotation, + args, + true + ) + ); + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisGet + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisSet + ); + return [field, getter, setter]; + } + + translateGetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + returnValue: arkts.Expression + ): arkts.MethodDefinition { + return createGetter(originalName, typeAnnotation, returnValue); + } + + translateSetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + statement: arkts.AstNode + ): arkts.MethodDefinition { + return createSetter2(originalName, typeAnnotation, statement); + } +} + +export class LocalStoragePropRefInterfaceTranslator< + T extends InterfacePropertyTypes +> extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `ILocalStoragePropRefDecoratedVariable | undefined`. + * + * @param method expecting getter with `@LocalStoragePropRef` and a setter with `@LocalStoragePropRef` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL_STORAGE_PROP_REF); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `ILocalStoragePropRefDecoratedVariable | undefined`. + * + * @param property expecting property with `@LocalStoragePropRef`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL_STORAGE_PROP_REF); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts index be59f9e6b9cd3c5d4817b5f9502f72077045d063..eae40f683e9b97e154bf85d2108187f274fa50b4 100755 --- a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts @@ -28,38 +28,10 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + getValueInAnnotation, } from './utils'; import { factory } from './factory'; -function getLocalStorageLinkValueStr(node: arkts.AstNode): string | undefined { - if (!arkts.isClassProperty(node) || !node.value) return undefined; - - return arkts.isStringLiteral(node.value) ? node.value.str : undefined; -} - -function getLocalStorageLinkAnnotationValue(anno: arkts.AnnotationUsage): string | undefined { - const isLocalStorageLinkAnnotation: boolean = - !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === DecoratorNames.LOCAL_STORAGE_LINK; - - if (isLocalStorageLinkAnnotation && anno.properties.length === 1) { - return getLocalStorageLinkValueStr(anno.properties.at(0)!); - } - return undefined; -} - -function getLocalStorageLinkValueInAnnotation(node: arkts.ClassProperty): string | undefined { - const annotations: readonly arkts.AnnotationUsage[] = node.annotations; - - for (let i = 0; i < annotations.length; i++) { - const anno: arkts.AnnotationUsage = annotations[i]; - const str: string | undefined = getLocalStorageLinkAnnotationValue(anno); - if (!!str) { - return str; - } - } - return undefined; -} - export class LocalStorageLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); @@ -79,7 +51,10 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { - const localStorageLinkValueStr: string | undefined = getLocalStorageLinkValueInAnnotation(this.property); + const localStorageLinkValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.LOCAL_STORAGE_LINK + ); if (!localStorageLinkValueStr) { throw new Error('LocalStorageLink required only one value!!'); } @@ -88,7 +63,7 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In arkts.factory.createStringLiteral(localStorageLinkValueStr), arkts.factory.create1StringLiteral(originalName), this.property.value ?? arkts.factory.createUndefinedLiteral(), - factory.createTypeFrom(this.property.typeAnnotation) + factory.createTypeFrom(this.property.typeAnnotation), ]; factory.judgeIfAddWatchFunc(args, this.property); collectStateManagementTypeImport(StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED); diff --git a/arkui-plugins/ui-plugins/property-translators/propRef.ts b/arkui-plugins/ui-plugins/property-translators/propRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..48328550604b1199e2ce085ae9a4d07a91371b4c --- /dev/null +++ b/arkui-plugins/ui-plugins/property-translators/propRef.ts @@ -0,0 +1,200 @@ +/* + * 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 { backingField, expectName } from '../../common/arkts-utils'; +import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { CustomComponentNames } from '../utils'; +import { + generateToRecord, + createGetter, + createSetter2, + generateGetOrSetCall, + generateThisBacking, + collectStateManagementTypeImport, + hasDecorator, + PropertyCache, +} from './utils'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; +import { GetterSetter, InitializerConstructor } from './types'; +import { factory } from './factory'; + +export class PropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { + translateMember(): arkts.AstNode[] { + const originalName: string = expectName(this.property.key); + const newName: string = backingField(originalName); + + this.cacheTranslatedInitializer(newName, originalName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string, originalName: string): void { + const mutableThis: arkts.Expression = generateThisBacking(newName); + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + const updateStruct: arkts.AstNode = this.generateUpdateStruct(mutableThis, originalName); + PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); + if (!!this.structInfo.annotations?.reusable) { + const toRecord = generateToRecord(newName, originalName); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); + } + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field: arkts.ClassProperty = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.PROP_REF_DECORATED, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisGet + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisSet + ); + + return [field, getter, setter]; + } + + translateGetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + returnValue: arkts.Expression + ): arkts.MethodDefinition { + return createGetter(originalName, typeAnnotation, returnValue); + } + + translateSetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + statement: arkts.AstNode + ): arkts.MethodDefinition { + return createSetter2(originalName, typeAnnotation, statement); + } + + generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { + const binaryItem = arkts.factory.createBinaryExpression( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + originalName + ), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING + ); + const args: arkts.Expression[] = [ + arkts.factory.create1StringLiteral(originalName), + this.property.value + ? binaryItem + : arkts.factory.createTSAsExpression( + factory.createNonNullOrOptionalMemberExpression( + CustomComponentNames.COMPONENT_INITIALIZERS_NAME, + originalName, + false, + true + ), + this.property.typeAnnotation?.clone(), + false + ), + ]; + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeImport(StateManagementTypes.PROP_REF_DECORATED); + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + factory.generateStateMgmtFactoryCall( + StateManagementTypes.MAKE_PROP_REF, + this.property.typeAnnotation, + args, + true + ) + ); + return arkts.factory.createExpressionStatement(assign); + } + + generateUpdateStruct(mutableThis: arkts.Expression, originalName: string): arkts.AstNode { + const member: arkts.MemberExpression = arkts.factory.createMemberExpression( + arkts.factory.createTSNonNullExpression(mutableThis), + arkts.factory.createIdentifier(StateManagementTypes.UPDATE), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ); + return factory.createIfInUpdateStruct(originalName, member, [ + arkts.factory.createTSAsExpression( + factory.createNonNullOrOptionalMemberExpression( + CustomComponentNames.COMPONENT_INITIALIZERS_NAME, + originalName, + false, + true + ), + this.property.typeAnnotation?.clone(), + false + ), + ]); + } +} + +export class PropRefInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROP_REF)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROP_REF)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `IPropRefDecoratedVariable | undefined`. + * + * @param method expecting getter with `@PropRef` and a setter with `@PropRef` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PROP_REF); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `IPropRefDecoratedVariable | undefined`. + * + * @param property expecting property with `@PropRef`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROP_REF); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index 7960157cd39293f2316635b8cf304232b5a095c7..f5d4a472458fea3bb175c44b16a5c5fd9922f652 100644 --- a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -20,7 +20,6 @@ import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; -import { updateArrow, updateNewClassInstanceExpression } from '../customdialog'; export class RegularPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { @@ -30,24 +29,10 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini return this.translateWithoutInitializer(newName, originalName); } - isCustomDialogController(node: arkts.AstNode | undefined): boolean { - if ((node instanceof arkts.ETSNewClassInstanceExpression) && (node.getTypeRef instanceof arkts.ETSTypeReference) && - (node.getTypeRef?.part?.name instanceof arkts.Identifier) && (node.getTypeRef?.part?.name?.name === 'CustomDialogController')) { - return true; - } - return false; - } - cacheTranslatedInitializer(newName: string, originalName: string): void { - const value = this.property.value; - if (this.isCustomDialogController(value)) { - const newValue = updateNewClassInstanceExpression(value as arkts.ETSNewClassInstanceExpression, this.property.key?.name, true); - const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName, newValue); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - } else { - const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName, value); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - } + const value = this.property.value ?? arkts.factory.createUndefinedLiteral(); + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName, value); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); diff --git a/arkui-plugins/ui-plugins/property-translators/storageProp.ts b/arkui-plugins/ui-plugins/property-translators/storageProp.ts index 8d3cf948a104b13fafed06bbb7f5c5fba9b92a7d..f1952c88da16e4964d5769321094407ac3629852 100644 --- a/arkui-plugins/ui-plugins/property-translators/storageProp.ts +++ b/arkui-plugins/ui-plugins/property-translators/storageProp.ts @@ -28,38 +28,10 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + getValueInAnnotation, } from './utils'; import { factory } from './factory'; -function getStoragePropValueStr(node: arkts.AstNode): string | undefined { - if (!arkts.isClassProperty(node) || !node.value) return undefined; - - return arkts.isStringLiteral(node.value) ? node.value.str : undefined; -} - -function getStoragePropAnnotationValue(anno: arkts.AnnotationUsage): string | undefined { - const isStoragePropAnnotation: boolean = - !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === DecoratorNames.STORAGE_PROP; - - if (isStoragePropAnnotation && anno.properties.length === 1) { - return getStoragePropValueStr(anno.properties.at(0)!); - } - return undefined; -} - -function getStoragePropValueInAnnotation(node: arkts.ClassProperty): string | undefined { - const annotations: readonly arkts.AnnotationUsage[] = node.annotations; - - for (let i = 0; i < annotations.length; i++) { - const anno: arkts.AnnotationUsage = annotations[i]; - const str: string | undefined = getStoragePropAnnotationValue(anno); - if (!!str) { - return str; - } - } - return undefined; -} - export class StoragePropTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); @@ -79,7 +51,10 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { - const storagePropValueStr: string | undefined = getStoragePropValueInAnnotation(this.property); + const storagePropValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.STORAGE_PROP + ); if (!storagePropValueStr) { throw new Error('StorageProp required only one value!!'); } @@ -88,7 +63,7 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial arkts.factory.createStringLiteral(storagePropValueStr), arkts.factory.create1StringLiteral(originalName), this.property.value ?? arkts.factory.createUndefinedLiteral(), - factory.createTypeFrom(this.property.typeAnnotation) + factory.createTypeFrom(this.property.typeAnnotation), ]; factory.judgeIfAddWatchFunc(args, this.property); collectStateManagementTypeImport(StateManagementTypes.STORAGE_PROP_REF_DECORATED); diff --git a/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts b/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..d14668cc72670d87d2d9a91cfd3fb6fe6987eeb4 --- /dev/null +++ b/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts @@ -0,0 +1,167 @@ +/* + * 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 { backingField, expectName } from '../../common/arkts-utils'; +import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; +import { GetterSetter, InitializerConstructor } from './types'; +import { + generateToRecord, + createGetter, + createSetter2, + generateThisBacking, + generateGetOrSetCall, + collectStateManagementTypeImport, + hasDecorator, + PropertyCache, + getValueInAnnotation, +} from './utils'; +import { factory } from './factory'; + +export class StoragePropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { + translateMember(): arkts.AstNode[] { + const originalName: string = expectName(this.property.key); + const newName: string = backingField(originalName); + + this.cacheTranslatedInitializer(newName, originalName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string, originalName: string): void { + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { + const toRecord = generateToRecord(newName, originalName); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); + } + } + + generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { + const storagePropValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.STORAGE_PROP_REF + ); + if (!storagePropValueStr) { + throw new Error('StoragePropRef required only one value!!'); + } + + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(storagePropValueStr), + arkts.factory.create1StringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + factory.createTypeFrom(this.property.typeAnnotation), + ]; + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_PROP_REF_DECORATED); + + return arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + factory.generateStateMgmtFactoryCall( + StateManagementTypes.MAKE_STORAGE_PROP_REF, + this.property.typeAnnotation, + args, + true + ) + ); + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.STORAGE_PROP_REF_DECORATED, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisGet + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisSet + ); + return [field, getter, setter]; + } + + translateGetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + returnValue: arkts.Expression + ): arkts.MethodDefinition { + return createGetter(originalName, typeAnnotation, returnValue); + } + + translateSetter( + originalName: string, + typeAnnotation: arkts.TypeNode | undefined, + statement: arkts.AstNode + ): arkts.MethodDefinition { + return createSetter2(originalName, typeAnnotation, statement); + } +} + +export class StoragePropRefInterfaceTranslator< + T extends InterfacePropertyTypes +> extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `IStoragePropRefDecoratedVariable | undefined`. + * + * @param method expecting getter with `@StoragePropRef` and a setter with `@StoragePropRef` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.STORAGE_PROP_REF); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `IStoragePropRefDecoratedVariable | undefined`. + * + * @param property expecting property with `@StoragePropRef`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STORAGE_PROP_REF); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/storagelink.ts b/arkui-plugins/ui-plugins/property-translators/storagelink.ts index 8c43bd631281a5166607bf3d38c188b8cc338833..579fe88329d9b5bef5605a452e260f76820d7129 100644 --- a/arkui-plugins/ui-plugins/property-translators/storagelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/storagelink.ts @@ -28,38 +28,10 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + getValueInAnnotation, } from './utils'; import { factory } from './factory'; -function getStorageLinkValueStr(node: arkts.AstNode): string | undefined { - if (!arkts.isClassProperty(node) || !node.value) return undefined; - - return arkts.isStringLiteral(node.value) ? node.value.str : undefined; -} - -function getStorageLinkAnnotationValue(anno: arkts.AnnotationUsage): string | undefined { - const isStorageLinkAnnotation: boolean = - !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === DecoratorNames.STORAGE_LINK; - - if (isStorageLinkAnnotation && anno.properties.length === 1) { - return getStorageLinkValueStr(anno.properties.at(0)!); - } - return undefined; -} - -function getStorageLinkValueInAnnotation(node: arkts.ClassProperty): string | undefined { - const annotations: readonly arkts.AnnotationUsage[] = node.annotations; - - for (let i = 0; i < annotations.length; i++) { - const anno: arkts.AnnotationUsage = annotations[i]; - const str: string | undefined = getStorageLinkAnnotationValue(anno); - if (!!str) { - return str; - } - } - return undefined; -} - export class StorageLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); @@ -79,7 +51,10 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { - const storageLinkValueStr: string | undefined = getStorageLinkValueInAnnotation(this.property); + const storageLinkValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.STORAGE_LINK + ); if (!storageLinkValueStr) { throw new Error('StorageLink required only one value!!'); } @@ -88,7 +63,7 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial arkts.factory.createStringLiteral(storageLinkValueStr), arkts.factory.create1StringLiteral(originalName), this.property.value ?? arkts.factory.createUndefinedLiteral(), - factory.createTypeFrom(this.property.typeAnnotation) + factory.createTypeFrom(this.property.typeAnnotation), ]; factory.judgeIfAddWatchFunc(args, this.property); collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_DECORATED); diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 56d189490329081257e09baec354e0f4ea0b92e2..4157572a951bab5d7ca637498723fa227168b7b1 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -98,7 +98,8 @@ export function needDefiniteOrOptionalModifier(st: arkts.ClassProperty): boolean hasDecoratorName(st, DecoratorNames.LINK) || hasDecoratorName(st, DecoratorNames.CONSUME) || hasDecoratorName(st, DecoratorNames.OBJECT_LINK) || - (hasDecoratorName(st, DecoratorNames.PROP) && !st.value) + (hasDecoratorName(st, DecoratorNames.PROP) && !st.value) || + (hasDecoratorName(st, DecoratorNames.PROP_REF) && !st.value) ); } @@ -137,15 +138,6 @@ export function findDecoratorInfos( return infos; } -export function getStateManagementType(decoratorInfo: DecoratorInfo): StateManagementTypes { - const decoratorName = decoratorInfo.name; - const typeName = DECORATOR_TYPE_MAP.get(decoratorName); - if (!!typeName) { - return typeName; - } - return StateManagementTypes.MUTABLE_STATE; -} - export function collectStateManagementTypeImport(type: StateManagementTypes): void { ImportCollector.getInstance().collectImport(type); } @@ -438,3 +430,4 @@ export class PropertyCache { this._cache.set(name, { ...this._cache.get(name), toRecordBody: newToRecordBody }); } } + diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 5901243d41b1c5e19f4042eeb56e44dd48cc7156..304c792b63b432d752dfa0416631e1c794e05c00 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -15,17 +15,20 @@ import * as arkts from '@koalaui/libarkts'; import { + BuilderLambdaNames, CustomComponentNames, + CustomDialogNames, getCustomComponentOptionsName, getGettersFromClassDecl, getTypeNameFromTypeParameter, getTypeParamsFromClassDecl, isCustomComponentInterface, - isKnownMethodDefinition + isCustomDialogControllerOptions, + isKnownMethodDefinition, } from '../utils'; import { factory as uiFactory } from '../ui-factory'; import { factory as propertyFactory } from '../property-translators/factory'; -import { collect, filterDefined } from '../../common/arkts-utils'; +import { backingField, collect, filterDefined } from '../../common/arkts-utils'; import { classifyObservedTrack, classifyProperty, @@ -47,8 +50,18 @@ import { getResourceParams, isResourceNode, isForEachCall, + getCustomDialogController, + isInvalidDialogControllerOptions, + findBuilderIndexInControllerOptions, + getControllerName, + DialogControllerInfo, } from './utils'; -import { collectStateManagementTypeImport, hasDecorator, PropertyCache } from '../property-translators/utils'; +import { + collectStateManagementTypeImport, + generateThisBacking, + hasDecorator, + PropertyCache, +} from '../property-translators/utils'; import { ProjectConfig } from '../../common/plugin-context'; import { ImportCollector } from '../../common/import-collector'; import { @@ -59,10 +72,12 @@ import { ModuleType, StateManagementTypes, RESOURCE_TYPE, + CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, } from '../../common/predefines'; import { ObservedTrackTranslator } from '../property-translators/observedTrack'; import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; import { generateArkUICompatible, isArkUICompatible } from '../interop/interop'; +import { GenSymGenerator } from '../../common/gensym-generator'; export class factory { /** @@ -84,7 +99,8 @@ export class factory { ); let body: arkts.BlockStatement | undefined; - let modifiers: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; + let modifiers: arkts.Es2pandaModifierFlags = + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; if (!scope.isDecl) { body = arkts.factory.createBlock(PropertyCache.getInstance().getInitializeBody(scope.name)); modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; @@ -112,6 +128,54 @@ export class factory { ); } + static transformControllerInterfaceType(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + if (!node.body || node.body.body.length <= 0 || !arkts.isMethodDefinition(node.body.body[0])) { + return node; + } + const updatedBody = arkts.factory.updateInterfaceBody(node.body, [ + this.updateBuilderType(node.body.body[0]), + ...node.body.body.slice(1), + ]); + return arkts.factory.updateInterfaceDeclaration( + node, + node.extends, + node.id, + node.typeParams, + updatedBody, + node.isStatic, + node.isFromExternal + ); + } + + static updateBuilderType(builderNode: arkts.MethodDefinition): arkts.MethodDefinition { + const newType: arkts.TypeNode | undefined = uiFactory.createTypeReferenceFromString( + CustomDialogNames.CUSTOM_BUILDER + ); + if (builderNode.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + const newOverLoads = builderNode.overloads.map((overload) => { + if (arkts.isMethodDefinition(overload)) { + return factory.updateBuilderType(overload); + } + return overload; + }); + builderNode.setOverloads(newOverLoads); + if (!!newType) { + builderNode.scriptFunction.setReturnTypeAnnotation(newType); + } + } else if (builderNode.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + const param = builderNode.scriptFunction.params[0] as arkts.ETSParameterExpression; + const newParam: arkts.Expression | undefined = arkts.factory.updateParameterDeclaration( + param, + arkts.factory.createIdentifier(param.identifier.name, newType), + param.initializer + ); + if (!!newParam) { + return uiFactory.updateMethodDefinition(builderNode, { function: { params: [newParam] } }); + } + } + return builderNode; + } + /** * create __updateStruct method. */ @@ -121,7 +185,8 @@ export class factory { ); let body: arkts.BlockStatement | undefined; - let modifiers: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; + let modifiers: arkts.Es2pandaModifierFlags = + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; if (!scope.isDecl) { body = arkts.factory.createBlock(PropertyCache.getInstance().getUpdateBody(scope.name)); modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; @@ -436,6 +501,16 @@ export class factory { classOptionsName ?? getCustomComponentOptionsName(className), scope ); + if (hasDecorator(node.definition, DecoratorNames.CUSTOM_DIALOG)) { + const dialogControllerProperty: arkts.ClassProperty | undefined = definition.body.find( + (item: arkts.AstNode) => arkts.isClassProperty(item) && getCustomDialogController(item).length > 0 + ) as arkts.ClassProperty | undefined; + if (!!dialogControllerProperty) { + translatedMembers.push( + this.createCustomDialogMethod(getCustomDialogController(dialogControllerProperty)) + ); + } + } const updateMembers: arkts.AstNode[] = definition.body .filter((member) => !arkts.isClassProperty(member)) .map((member: arkts.AstNode) => factory.transformNonPropertyMembersInClass(member, scope.isDecl)); @@ -523,6 +598,48 @@ export class factory { } } + static createCustomDialogMethod(controller: string): arkts.MethodDefinition { + const param: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + CustomDialogNames.CONTROLLER, + uiFactory.createTypeReferenceFromString(CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) + ), + undefined + ); + const block = arkts.factory.createBlock( + controller.length !== 0 + ? [ + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(backingField(controller)), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + arkts.factory.createIdentifier(CustomDialogNames.CONTROLLER) + ) + ), + ] + : [] + ); + const script = arkts.factory.createScriptFunction( + block, + arkts.FunctionSignature.createFunctionSignature( + undefined, + [param], + arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false + ), + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ); + + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + arkts.factory.createIdentifier(CustomDialogNames.SET_DIALOG_CONTROLLER_METHOD), + script, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + } + /* * Process string Literal type arguments for $r node. */ @@ -607,6 +724,9 @@ export class factory { if (externalSourceName === ARKUI_COMPONENT_COMMON_SOURCE_NAME && node.id.name === 'CommonMethod') { return factory.modifyExternalComponentCommon(node); } + if (isCustomDialogControllerOptions(node, externalSourceName)) { + return factory.transformControllerInterfaceType(node); + } if (isCustomComponentInterface(node)) { return factory.tranformCustomComponentInterfaceMembers(node); } @@ -926,4 +1046,198 @@ export class factory { } return node; } + + static transformCustomDialogController( + node: arkts.ETSNewClassInstanceExpression + ): arkts.ETSNewClassInstanceExpression | arkts.Expression { + if (isInvalidDialogControllerOptions(node.getArguments)) { + throw new Error('Error CustomDialogOptions'); + } + const optionArg = node.getArguments[0]; + const options: arkts.ObjectExpression = arkts.isObjectExpression(optionArg) + ? optionArg + : ((optionArg as arkts.TSAsExpression).expr as arkts.ObjectExpression); + const builderIndex: number = findBuilderIndexInControllerOptions(options.properties); + if (builderIndex < 0 || !(options.properties[builderIndex] as arkts.Property).value) { + throw new Error('Error CustomDialogOptions'); + } + const builder: arkts.Property = options.properties[builderIndex] as arkts.Property; + const controllerInfo: DialogControllerInfo = getControllerName(node); + const gensymName: string = GenSymGenerator.getInstance().id(controllerInfo.controllerName); + const newBuilderValue = this.createDialogBuilderArrow(builder.value!, controllerInfo, gensymName); + const newProperty = arkts.factory.updateProperty(builder, builder.key, newBuilderValue); + const newObj = arkts.factory.updateObjectExpression( + options, + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + [ + ...(options.properties as arkts.Property[]).slice(0, builderIndex), + newProperty, + ...(options.properties as arkts.Property[]).slice(builderIndex + 1), + this.createBaseComponent(), + ], + false + ); + const newOptions = arkts.isTSAsExpression(optionArg) + ? arkts.factory.updateTSAsExpression(optionArg, newObj, optionArg.typeAnnotation, optionArg.isConst) + : newObj; + const typeRef = node.getTypeRef as arkts.ETSTypeReference; + const newNode = arkts.factory.updateETSNewClassInstanceExpression(node, typeRef, [newOptions]); + if (controllerInfo.parent && arkts.isVariableDeclarator(controllerInfo.parent)) { + return factory.createBlockStatementForOptionalExpression(controllerInfo.parent, newNode, gensymName); + } + return newNode; + } + + static createDialogBuilderArrow( + value: arkts.Expression, + controllerInfo: DialogControllerInfo, + gensymName: string + ): arkts.Expression { + if ( + arkts.isCallExpression(value) && + arkts.isMemberExpression(value.expression) && + arkts.isIdentifier(value.expression.property) && + value.expression.property.name === BuilderLambdaNames.TRANSFORM_METHOD_NAME + ) { + return addMemoAnnotation( + arkts.factory.createArrowFunction( + uiFactory.createScriptFunction({ + body: arkts.factory.createBlock([ + arkts.factory.createExpressionStatement( + this.transformCustomDialogComponentCall(value, controllerInfo, gensymName) + ), + ]), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + }) + ) + ); + } + if (arkts.isArrowFunctionExpression(value)) { + return addMemoAnnotation(value); + } + return value; + } + + static transformCustomDialogComponentCall( + value: arkts.CallExpression, + controllerInfo: DialogControllerInfo, + gensymName: string + ): arkts.CallExpression { + if (value.arguments.length >= 2 && arkts.isArrowFunctionExpression(value.arguments[1])) { + const originScript: arkts.ScriptFunction = value.arguments[1].scriptFunction; + const newScript: arkts.ScriptFunction = uiFactory.updateScriptFunction(originScript, { + body: this.generateInstanceSetController(originScript.body, controllerInfo, gensymName), + }); + return arkts.factory.updateCallExpression(value, value.expression, value.typeArguments, [ + value.arguments[0], + arkts.factory.updateArrowFunction(value.arguments[1], newScript), + ...value.arguments.slice(2), + ]); + } + return value; + } + + static generateInstanceSetController( + body: arkts.AstNode | undefined, + controllerInfo: DialogControllerInfo, + gensymName: string + ): arkts.AstNode | undefined { + if ( + !!body && + arkts.isBlockStatement(body) && + body.statements.length > 0 && + arkts.isReturnStatement(body.statements[0]) + ) { + const instanceIdent: arkts.Identifier = arkts.factory.createIdentifier( + BuilderLambdaNames.STYLE_ARROW_PARAM_NAME + ); + return arkts.factory.updateBlock(body, [ + arkts.factory.createVariableDeclaration( + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONST, + arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_CONST, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_CONST, + instanceIdent, + body.statements[0].argument?.clone() + ), + ] + ), + this.genertateControllerSetCall(instanceIdent, controllerInfo, gensymName), + arkts.factory.createReturnStatement(instanceIdent.clone()), + ]); + } + return body; + } + + static genertateControllerSetCall( + instanceIdent: arkts.Identifier, + controllerInfo: DialogControllerInfo, + gensymName: string + ): arkts.AstNode { + return arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + instanceIdent.clone(), + arkts.factory.createIdentifier(CustomDialogNames.SET_DIALOG_CONTROLLER_METHOD), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + undefined, + [ + arkts.factory.createTSAsExpression( + controllerInfo.isClassProperty + ? generateThisBacking(controllerInfo.controllerName) + : arkts.factory.createIdentifier(gensymName), + uiFactory.createTypeReferenceFromString(CustomDialogNames.CUSTOM_DIALOG_CONTROLLER), + false + ), + ] + ) + ); + } + + static createBaseComponent(): arkts.Property { + return arkts.factory.createProperty( + arkts.factory.createIdentifier(CustomDialogNames.BASE_COMPONENT), + arkts.factory.createThisExpression() + ); + } + + static generateLetVariableDecl(left: arkts.Identifier): arkts.VariableDeclaration { + return arkts.factory.createVariableDeclaration( + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, + left, + undefined + ), + ] + ); + } + + static createBlockStatementForOptionalExpression( + variableNode: arkts.VariableDeclarator, + newNode: arkts.ETSNewClassInstanceExpression, + gensymName: string + ): arkts.Expression { + const statements: arkts.Statement[] = [ + factory.generateLetVariableDecl( + arkts.factory.createIdentifier(gensymName, variableNode.name.typeAnnotation) + ), + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + arkts.factory.createIdentifier(gensymName), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + newNode + ) + ), + arkts.factory.createExpressionStatement(arkts.factory.createIdentifier(gensymName)), + ]; + return arkts.factory.createBlockExpression(statements); + } } diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index bb3123e317cceecd15fc5ecf8ac7e5531876e5d1..fb952880f566f6829ecb3fc49d8f56872e93f128 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -16,7 +16,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as arkts from '@koalaui/libarkts'; -import { CustomComponentInfo } from '../utils'; +import { CustomComponentInfo, CustomDialogNames } from '../utils'; import { matchPrefix } from '../../common/arkts-utils'; import { ARKUI_IMPORT_PREFIX_NAMES, @@ -63,6 +63,12 @@ export interface ResourceParameter { params: arkts.Expression[]; } +export interface DialogControllerInfo { + controllerName: string; + isClassProperty: boolean; + parent?: arkts.AstNode; +} + export function getResourceParams(id: number, type: number, params: arkts.Expression[]): ResourceParameter { return { id, type, params }; } @@ -520,3 +526,75 @@ export function isForEachDecl(node: arkts.MethodDefinition, sourceName: string | 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 = ''; + if (!(key && arkts.isIdentifier(key) && node.typeAnnotation)) { + return ''; + } + const typeAnno = node.typeAnnotation; + if (arkts.isETSUnionType(typeAnno)) { + for (const type of typeAnno.types) { + if (arkts.isETSTypeReference(type)) { + controllerName = hasController(type, key.name); + } + } + } else if (arkts.isETSTypeReference(typeAnno)) { + controllerName = hasController(typeAnno, key.name); + } + return controllerName; +} + +export function hasController(node: arkts.ETSTypeReference, keyName: string): string { + const ident = node.part?.name; + if (ident && arkts.isIdentifier(ident) && ident.name === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) { + return keyName; + } + return ''; +} + +export function isInvalidDialogControllerOptions(args: readonly arkts.Expression[]): boolean { + const firstOptionsParameter: arkts.AstNode = args[0]; + return ( + args.length <= 0 || + !(isObjectAsExpression(firstOptionsParameter) || arkts.isObjectExpression(firstOptionsParameter)) + ); +} + +function isObjectAsExpression(param: arkts.AstNode): boolean { + return arkts.isTSAsExpression(param) && !!param.expr && arkts.isObjectExpression(param.expr); +} + +export function findBuilderIndexInControllerOptions(properties: readonly arkts.Expression[]): number { + return properties.findIndex((item: arkts.Expression) => { + return ( + arkts.isProperty(item) && + !!item.key && + arkts.isIdentifier(item.key) && + item.key.name === CustomDialogNames.OPTIONS_BUILDER + ); + }); +} + +export function getControllerName(node: arkts.ETSNewClassInstanceExpression): DialogControllerInfo { + let controllerName: string = ''; + let isClassProperty: boolean = false; + let parent: arkts.AstNode | undefined = node.parent; + if (!parent) { + return { controllerName, isClassProperty }; + } + while (!!parent && !arkts.isClassDefinition(parent)) { + if (arkts.isClassProperty(parent) && parent.key && arkts.isIdentifier(parent.key)) { + controllerName = parent.key.name; + isClassProperty = true; + break; + } else if (arkts.isVariableDeclarator(parent)) { + controllerName = parent.name.name; + break; + } + parent = parent?.parent; + } + + return { controllerName, isClassProperty, parent }; +} diff --git a/arkui-plugins/ui-plugins/ui-factory.ts b/arkui-plugins/ui-plugins/ui-factory.ts index ca8dd32bf427d90631cf343cbb11931d880a8606..9c204231a786f1ce3e43566236bd9708801668bf 100644 --- a/arkui-plugins/ui-plugins/ui-factory.ts +++ b/arkui-plugins/ui-plugins/ui-factory.ts @@ -18,6 +18,7 @@ import { BuilderLambdaNames, CustomComponentAnontations, CustomComponentNames, + CustomDialogNames, hasNullOrUndefinedType, hasPropertyInAnnotation, } from './utils'; @@ -397,4 +398,47 @@ export class factory { } return implementsInfo; } + + /** + * create class property node: `:`. + * + * @param method method definition node + */ + static createPropertyInInterface(key: string, type?: arkts.TypeNode): arkts.ClassProperty { + const keyIdent: arkts.Identifier = arkts.factory.createIdentifier(key); + return arkts.factory.createClassProperty( + keyIdent, + undefined, + type, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL, + false + ); + } + + /** + * add `baseComponent: ExtendableComponent` to interface CustomDialogControllerOptions. + * + * @param method method definition node + */ + static updateCustomDialogOptionsInterface(newNode: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + if (!newNode.body?.body || newNode.body?.body.length <= 0) { + return newNode; + } + + return arkts.factory.updateInterfaceDeclaration( + newNode, + newNode.extends, + newNode.id, + newNode.typeParams, + arkts.factory.updateInterfaceBody(newNode.body!, [ + ...newNode.body.body, + factory.createPropertyInInterface( + CustomDialogNames.BASE_COMPONENT, + factory.createTypeReferenceFromString(CustomDialogNames.EXTENDABLE_COMPONENT) + ), + ]), + newNode.isStatic, + newNode.isFromExternal + ); + } } diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index 562c74f4ed6619f53fcd07cf76251a9d9a615122..5eb026379600a7bd3e54b5a41f32073aa7be23d4 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -15,7 +15,11 @@ import * as arkts from '@koalaui/libarkts'; import { matchPrefix } from '../common/arkts-utils'; -import { ARKUI_IMPORT_PREFIX_NAMES, StructDecoratorNames } from '../common/predefines'; +import { + ARKUI_IMPORT_PREFIX_NAMES, + CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, + StructDecoratorNames, +} from '../common/predefines'; import { DeclarationCollector } from '../common/declaration-collector'; export enum CustomComponentNames { @@ -23,6 +27,7 @@ export enum CustomComponentNames { COMPONENT_CONSTRUCTOR_ORI = 'constructor', COMPONENT_CLASS_NAME = 'CustomComponent', COMPONENT_V2_CLASS_NAME = 'CustomComponentV2', + BASE_CUSTOM_DIALOG_NAME = 'BaseCustomDialog', COMPONENT_INTERFACE_PREFIX = '__Options_', COMPONENT_INITIALIZE_STRUCT = '__initializeStruct', COMPONENT_UPDATE_STRUCT = '__updateStruct', @@ -31,10 +36,18 @@ export enum CustomComponentNames { OPTIONS = 'options', PAGE_LIFE_CYCLE = 'PageLifeCycle', LAYOUT_CALLBACK = 'LayoutCallback', - CUSTOMDIALOG_ANNOTATION_NAME = 'CustomDialog', - CUSTOMDIALOG_CONTROLLER = 'CustomDialogController', - CUSTOMDIALOG_CONTROLLER_OPTIONS = 'CustomDialogControllerOptions', - SETDIALOGCONTROLLER_METHOD = '__setDialogController__', +} + +export enum CustomDialogNames { + CUSTOM_DIALOG_ANNOTATION_NAME = 'CustomDialog', + CUSTOM_DIALOG_CONTROLLER = 'CustomDialogController', + CUSTOM_DIALOG_CONTROLLER_OPTIONS = 'CustomDialogControllerOptions', + SET_DIALOG_CONTROLLER_METHOD = '__setDialogController__', + CONTROLLER = 'controller', + OPTIONS_BUILDER = 'builder', + BASE_COMPONENT = 'baseComponent', + EXTENDABLE_COMPONENT = 'ExtendableComponent', + CUSTOM_BUILDER = 'CustomBuilder', } export enum BuilderLambdaNames { @@ -43,7 +56,7 @@ export enum BuilderLambdaNames { TRANSFORM_METHOD_NAME = '_instantiateImpl', STYLE_PARAM_NAME = 'style', STYLE_ARROW_PARAM_NAME = 'instance', - CONTENT_PARAM_NAME = 'content' + CONTENT_PARAM_NAME = 'content', } // IMPORT @@ -156,6 +169,13 @@ type StructAnnoationInfo = { isCustomDialog: boolean; }; +export type ComponentType = { + hasComponent: boolean; + hasComponentV2: boolean; + hasCustomDialog: boolean; + hasCustomLayout: boolean; +}; + export function isCustomComponentAnnotation( anno: arkts.AnnotationUsage, decoratorName: StructDecoratorNames, @@ -264,7 +284,9 @@ export function isCustomComponentClass(node: arkts.ClassDeclaration, scopeInfo: export function isCustomComponentInterface(node: arkts.TSInterfaceDeclaration): boolean { const checkPrefix = !!node.id?.name.startsWith(CustomComponentNames.COMPONENT_INTERFACE_PREFIX); const checkComponent = node.annotations.some((anno) => - isCustomComponentAnnotation(anno, StructDecoratorNames.COMPONENT) + isCustomComponentAnnotation(anno, StructDecoratorNames.COMPONENT) || + isCustomComponentAnnotation(anno, StructDecoratorNames.COMPONENT_V2) || + isCustomComponentAnnotation(anno, StructDecoratorNames.CUSTOMDIALOG) ); return checkPrefix && checkComponent; } @@ -288,3 +310,45 @@ export function isKnownMethodDefinition(method: arkts.MethodDefinition, name: st const isNameMatched: boolean = method.name?.name === name; return isNameMatched; } + +export function isSpecificNewClass(node: arkts.ETSNewClassInstanceExpression, className: string): boolean { + if ( + node.getTypeRef && + arkts.isETSTypeReference(node.getTypeRef) && + node.getTypeRef.part && + arkts.isETSTypeReferencePart(node.getTypeRef.part) && + node.getTypeRef.part.name && + arkts.isIdentifier(node.getTypeRef.part.name) && + node.getTypeRef.part.name.name === className + ) { + return true; + } + return false; +} + +export function isCustomDialogControllerOptions( + newNode: arkts.TSInterfaceDeclaration, + externalSourceName: string | undefined +): boolean { + return ( + externalSourceName === CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME && + !!newNode.id && + newNode.id.name === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER_OPTIONS + ); +} + +export function getComponentExtendsName(annotations: CustomComponentAnontations, componentType: ComponentType): string { + if (!!annotations.customLayout) { + componentType.hasCustomLayout ||= true; + } + if (!!annotations.customdialog) { + componentType.hasCustomDialog ||= true; + return CustomComponentNames.BASE_CUSTOM_DIALOG_NAME; + } + if (!!annotations.componentV2) { + componentType.hasComponentV2 ||= true; + return CustomComponentNames.COMPONENT_V2_CLASS_NAME; + } + componentType.hasComponent ||= true; + return CustomComponentNames.COMPONENT_CLASS_NAME; +}