1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import * as path from 'path'; 17import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; 18import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; 19import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; 20import { parseDumpSrc } from '../../../../utils/parse-string'; 21import { recheck, uiNoRecheck } from '../../../../utils/plugins'; 22import { uiTransform } from '../../../../../ui-plugins'; 23import { Plugins } from '../../../../../common/plugin-context'; 24 25const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; 26const CUSTOM_COMPONENT_DIR_PATH: string = 'custom-component'; 27 28const buildConfig: BuildConfig = mockBuildConfig(); 29buildConfig.compileFiles = [ 30 path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, CUSTOM_COMPONENT_DIR_PATH, 'custom-component-call.ets'), 31]; 32 33const pluginTester = new PluginTester('test custom component call transformation', buildConfig); 34 35const parsedTransform: Plugins = { 36 name: 'custom-component-call', 37 parsed: uiTransform().parsed 38}; 39 40const expectedParsedScript: string = ` 41import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; 42import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; 43import { memo as memo } from "@ohos.arkui.stateManagement"; 44import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; 45import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; 46import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; 47import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; 48 49@Component() final class CustomContainer extends CustomComponent<CustomContainer, __Options_CustomContainer> { 50 @Builder() public closerBuilder() {} 51 @BuilderParam() public closer: (()=> void) = (this).closerBuilder; 52 public build() {} 53 public constructor() {} 54} 55 56@Component() final class CustomContainerUser extends CustomComponent<CustomContainerUser, __Options_CustomContainerUser> { 57 public build() { 58 Column(undefined){ 59 CustomContainer(undefined){ 60 Column(undefined){ 61 Text("hello", undefined); 62 }; 63 }; 64 CustomContainer(({} as __Options_CustomContainer)){ 65 Column(undefined){}; 66 }; 67 CustomContainer(undefined){}; 68 CustomContainer(); 69 }; 70 } 71 public constructor() {} 72} 73 74interface __Options_CustomContainer { 75 closer?: @memo() (()=> void); 76} 77 78interface __Options_CustomContainerUser { 79} 80`; 81 82function testParedTransformer(this: PluginTestContext): void { 83 expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedParsedScript)); 84} 85 86const expectedBuilderLambdaScript: string = ` 87import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; 88import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; 89import { memo as memo } from "@ohos.arkui.stateManagement"; 90import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; 91import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; 92import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; 93import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; 94 95function main() {} 96 97@Component({freezeWhenInactive:false}) final class CustomContainer extends CustomComponent<CustomContainer, __Options_CustomContainer> { 98 public __initializeStruct(initializers: __Options_CustomContainer | undefined, @memo() content: (()=> void) | undefined): void { 99 (this).__backing_closer = ((((({let gensym___38813563 = initializers; 100 (((gensym___38813563) == (null)) ? undefined : gensym___38813563.closer)})) ?? (content))) ?? ((this).closerBuilder)) 101 } 102 public __updateStruct(initializers: __Options_CustomContainer | undefined): void {} 103 private __backing_closer?: @memo() (()=> void); 104 public get closer(): @memo() (()=> void) { 105 return (this).__backing_closer!; 106 } 107 public set closer(@memo() value: (()=> void)) { 108 (this).__backing_closer = value; 109 } 110 @memo() public closerBuilder() {} 111 @memo() public _build(@memo() style: ((instance: CustomContainer)=> CustomContainer) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_CustomContainer | undefined): void {} 112 public constructor() {} 113} 114 115@Component({freezeWhenInactive:false}) final class CustomContainerUser extends CustomComponent<CustomContainerUser, __Options_CustomContainerUser> { 116 public __initializeStruct(initializers: __Options_CustomContainerUser | undefined, @memo() content: (()=> void) | undefined): void {} 117 public __updateStruct(initializers: __Options_CustomContainerUser | undefined): void {} 118 @memo() public _build(@memo() style: ((instance: CustomContainerUser)=> CustomContainerUser) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_CustomContainerUser | undefined): void { 119 Column(undefined, undefined, (() => { 120 CustomContainer._instantiateImpl(undefined, (() => { 121 return new CustomContainer(); 122 }), undefined, (() => { 123 Column(undefined, undefined, (() => { 124 Text(undefined, "hello", undefined, undefined); 125 })); 126 }), undefined); 127 CustomContainer._instantiateImpl(undefined, (() => { 128 return new CustomContainer(); 129 }), ({} as __Options_CustomContainer), (() => { 130 Column(undefined, undefined, (() => {})); 131 }), undefined); 132 CustomContainer._instantiateImpl(undefined, (() => { 133 return new CustomContainer(); 134 }), undefined, (() => {}), undefined); 135 CustomContainer._instantiateImpl(undefined, (() => { 136 return new CustomContainer(); 137 }), undefined, undefined, undefined); 138 })); 139 } 140 public constructor() {} 141} 142 143interface __Options_CustomContainer { 144 set closer(closer: @memo() (()=> void) | undefined) 145 get closer(): @memo() (()=> void) | undefined 146} 147 148interface __Options_CustomContainerUser { 149} 150`; 151 152function testCustomComponentTransformer(this: PluginTestContext): void { 153 expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedBuilderLambdaScript)); 154} 155 156pluginTester.run( 157 'test custom component call transformation', 158 [parsedTransform, recheck, uiNoRecheck], 159 { 160 parsed: [testParedTransformer], 161 'checked:builder-lambda-no-recheck': [testCustomComponentTransformer], 162 }, 163 { 164 stopAfter: 'checked', 165 } 166); 167