diff --git a/arkui-plugins/ui-plugins/interop/initstatevar.ts b/arkui-plugins/ui-plugins/interop/initstatevar.ts index 14225718e759121074bfcb9f97b4ab87748d3c78..1f43c179e015d9c039e977070a2f1c661c4c057b 100644 --- a/arkui-plugins/ui-plugins/interop/initstatevar.ts +++ b/arkui-plugins/ui-plugins/interop/initstatevar.ts @@ -231,7 +231,9 @@ export function processNormal(keyName: string, value: arkts.AstNode): arkts.Stat */ export function processBuilderParam(keyName: string, value: arkts.AstNode): arkts.Statement[] { const result: arkts.Statement[] = []; + const needUpdate: boolean = checkUpdatable(value); const newValue = arkts.factory.createCallExpression( + needUpdate ? arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER) : arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER), undefined, [ @@ -245,4 +247,59 @@ export function processBuilderParam(keyName: string, value: arkts.AstNode): arkt ); result.push(setProperty); return result; +} + +function getIdentifier(value: arkts.AstNode): arkts.identifier | undefined { + if (arkts.isIdentifier(value)) { + return value; + } else if (arkts.isMemberExpression(value) && arkts.isThisExpression(value.object) && arkts.isIdentifier(value.property)) { + return value.property; + } else { + return undefined; + } +} + +function checkUpdatable(value: arkts.AstNode): boolean { + const ident = getIdentifier(value); + if (ident === undefined) { + return false; + } + const decl = arkts.getDecl(ident) as arkts.MethodDefinition; + const script = decl.scriptFunction; + const params = script.params; + if (params.length === 1 && arkts.isEtsParameterExpression(params[0])) { + const type = params[0].type; + if (type === undefined) { + return false; + } + if (arkts.isETSUnionType(type)) { + for (const element of type.types) { + if (isNonBuiltinType(element)) { + return true; + } + } + } else if (isNonBuiltinType(type)) { + return true; + } + } + return false; +} + +function isNonBuiltinType(type: arkts.AstNode): boolean { + if (!arkts.isETSTypeReference(type)) { + return false; + } + const ident = type.part?.name; + if (ident && arkts.isIdentifier(ident)) { + const decl = arkts.getDecl(ident); + if (!decl) { + return false; + } + const moduleName = arkts.getProgramFromAstNode(decl).moduleName; + if (moduleName === 'escompat') { + return false; + } + return true; + } + return false; } \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/interop/interop.ts b/arkui-plugins/ui-plugins/interop/interop.ts index 8da4bc6d59e6567f8d924e9ead065ab5a57c86dc..5544444107e055b8b6186686a3fb034159bef282 100644 --- a/arkui-plugins/ui-plugins/interop/interop.ts +++ b/arkui-plugins/ui-plugins/interop/interop.ts @@ -402,6 +402,8 @@ export function isArkUICompatible(node: arkts.AstNode): boolean { ImportCollector.getInstance().collectImport(InteroperAbilityNames.GETCOMPATIBLESTATE); ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER, InteroperAbilityNames.INTEROP); ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER); + ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER, InteroperAbilityNames.INTEROP); + ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER); return true; } return false; diff --git a/arkui-plugins/ui-plugins/interop/predefines.ts b/arkui-plugins/ui-plugins/interop/predefines.ts index 1a8f5deabafc0a57c08b0e1d2eedba62543646fd..5eec3bffe8c95d679c61b5054cd9a25512503847 100644 --- a/arkui-plugins/ui-plugins/interop/predefines.ts +++ b/arkui-plugins/ui-plugins/interop/predefines.ts @@ -65,6 +65,7 @@ export enum BuilderMethodNames { RUNPENDINGJOBS = 'runPendingJobs', CREATECOMPATIBLENODE = 'createCompatibleNode', TRANSFERCOMPATIBLEBUILDER = 'transferCompatibleBuilder', + TRANSFERCOMPATIBLEUPDATABLEBUILDER = 'transferCompatibleUpdatableBuilder', } export enum BuilderParams { diff --git a/compiler/src/interop/src/pre_define.ts b/compiler/src/interop/src/pre_define.ts index a044b786cfd8fd643bcff3ae478553e7f916cfeb..6605153d6f17fa4da9ce86574070821824800510 100644 --- a/compiler/src/interop/src/pre_define.ts +++ b/compiler/src/interop/src/pre_define.ts @@ -623,6 +623,7 @@ export const RESERT = 'reset'; export const TS_NOCHECK: string = '// @ts-nocheck'; export const BUILDER_PARAM_PROXY: string = 'makeBuilderParameterProxy'; +export const BUILDER_PARAM_PROXY_INTEROP: string = '__makeBuilderParameterStaticProxy_Interop_Internal'; export const BUILDER_TYPE: string = 'BuilderType'; export const FUNCTION: string = 'function'; diff --git a/compiler/src/interop/src/process_component_build.ts b/compiler/src/interop/src/process_component_build.ts index 037efb0b8bacb4900450d2a806c195ec7691fe8a..4956abd647321f724e033cebc911f07551e50452 100644 --- a/compiler/src/interop/src/process_component_build.ts +++ b/compiler/src/interop/src/process_component_build.ts @@ -203,6 +203,7 @@ import { concatenateEtsOptions, getExternalComponentPaths } from './external_component_map'; +import { isStaticObjectLiteral, updateInteropObjectLiteralxpression } from './process_interop_builder'; export function processComponentBuild(node: ts.MethodDeclaration, log: LogInfo[]): ts.MethodDeclaration { @@ -612,30 +613,33 @@ export function transferBuilderCall(node: ts.ExpressionStatement, name: string, if (node.expression && ts.isCallExpression(node.expression)) { let newNode: ts.Expression = builderCallNode(node.expression); newNode.expression.questionDotToken = node.expression.questionDotToken; - if (node.expression.arguments && node.expression.arguments.length === 1 && ts.isObjectLiteralExpression(node.expression.arguments[0])) { - return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( - node.expression, - newNode, - undefined, - [ts.factory.createCallExpression( - ts.factory.createIdentifier(BUILDER_PARAM_PROXY), + if (node.expression.arguments && node.expression.arguments.length === 1) { + if (ts.isObjectLiteralExpression(node.expression.arguments[0])) { + return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( + node.expression, + newNode, undefined, - [ - ts.factory.createStringLiteral(name), - traverseBuilderParams(node.expression.arguments[0], isBuilder) - ] - )] - )); - } else { - return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( - node.expression, - newNode, - undefined, - !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach && - storedFileInfo.lazyForEachInfo.forEachParameters || isBuilder)) ? node.expression.arguments : - [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)] - )); + [ts.factory.createCallExpression( + ts.factory.createIdentifier(BUILDER_PARAM_PROXY), + undefined, + [ + ts.factory.createStringLiteral(name), + traverseBuilderParams(node.expression.arguments[0], isBuilder) + ] + )] + )); + } else if (isStaticObjectLiteral(node.expression.arguments[0])) { + return updateInteropObjectLiteralxpression(node.expression, newNode, name); + } } + return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( + node.expression, + newNode, + undefined, + !(projectConfig.optLazyForEach && (storedFileInfo.processLazyForEach && + storedFileInfo.lazyForEachInfo.forEachParameters || isBuilder)) ? node.expression.arguments : + [...node.expression.arguments, ts.factory.createNull(), ts.factory.createIdentifier(MY_IDS)] + )); } return undefined; } diff --git a/compiler/src/interop/src/process_interop_builder.ts b/compiler/src/interop/src/process_interop_builder.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f83f99b920467b2e98e646bcf3eeece2284f203 --- /dev/null +++ b/compiler/src/interop/src/process_interop_builder.ts @@ -0,0 +1,78 @@ +/* + * 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 ts from 'typescript'; +import { BUILDER_PARAM_PROXY_INTEROP } from './pre_define'; + +export function isStaticObjectLiteral(node: ts.Expression): boolean { + if (ts.isParenthesizedExpression(node) && ts.isCommaListExpression(node.expression)) { + const list = node.expression.elements; + const lastNode = list[list.length - 1]; + if (ts.isIdentifier(lastNode) && lastNode.text.startsWith('tmpObj')) { + return true; + } + } + return false; +} + +function processObjectLiteral(properties: ts.ObjectLiteralElementLike[], node: ts.ParenthesizedExpression): void { + const list = (node.expression as ts.CommaListExpression).elements; + list.forEach(node => { + if (ts.isBinaryExpression(node) && ts.isPropertyAccessExpression(node.left)) { + const keyName = node.left.name.text; + if (ts.isPropertyAccessExpression(node.right) && node.right.expression.kind === ts.SyntaxKind.ThisKeyword) { + const name = node.right.name.text; + properties.push(ts.factory.createPropertyAssignment( + keyName, + ts.factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createElementAccessExpression( + ts.factory.createThis(), + ts.factory.createStringLiteral(name) + ) + ) + )); + } else { + properties.push(ts.factory.createPropertyAssignment( + keyName, + node.right + )); + } + } + }); +} + +export function updateInteropObjectLiteralxpression(origin: ts.CallExpression, newNode:ts.Expression, name: string): ts.ExpressionStatement { + const properties: ts.ObjectLiteralElementLike[] = []; + processObjectLiteral(properties, origin.arguments[0] as ts.ParenthesizedExpression); + return ts.factory.createExpressionStatement(ts.factory.updateCallExpression( + origin, + newNode, + undefined, + [ts.factory.createCallExpression( + ts.factory.createIdentifier(BUILDER_PARAM_PROXY_INTEROP), + undefined, + [ + ts.factory.createStringLiteral(name), + origin.arguments[0], + ts.factory.createObjectLiteralExpression(properties), + ] + )] + )); +} diff --git a/compiler/src/interop/src/process_interop_ui.ts b/compiler/src/interop/src/process_interop_ui.ts index 4907c40ae6f67f79a2343b141238b25f99c3429a..cad3fcdde73bfb562fdd61282ef2a9bd7ae476c0 100644 --- a/compiler/src/interop/src/process_interop_ui.ts +++ b/compiler/src/interop/src/process_interop_ui.ts @@ -168,7 +168,8 @@ class HandleUIImports { const interopImportName = [ 'compatibleComponent', 'getCompatibleState', - 'transferCompatibleBuilder' + 'transferCompatibleBuilder', + 'transferCompatibleUpdatableBuilder' ]; const interopImportSpecifiers: ts.ImportSpecifier[] = []; interopImportName.forEach((interopName) => {