diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index 16065cfe8302595283b819027ca773afbda255a1..6e51e18f7f1eba1e916fb68d3240cdc7d7cfe67d 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -73,6 +73,7 @@ export enum StructDecoratorNames { RESUABLE = 'Reusable', RESUABLE_V2 = 'ReusableV2', CUSTOM_LAYOUT = 'CustomLayout', + CUSTOMDIALOG = 'CustomDialog', } export enum DecoratorNames { diff --git a/arkui-plugins/memo-plugins/utils.ts b/arkui-plugins/memo-plugins/utils.ts index 51a17d0321eac6b9591a81ce75caa7ff7877d476..31cb1ff549ed69e08669616d60621cdbbd3be071 100644 --- a/arkui-plugins/memo-plugins/utils.ts +++ b/arkui-plugins/memo-plugins/utils.ts @@ -451,7 +451,7 @@ export function findMemoFromTypeAnnotation(typeAnnotation: arkts.AstNode | undef if (arkts.isETSTypeReference(typeAnnotation) && !!typeAnnotation.part && !!typeAnnotation.part.name) { let decl: arkts.AstNode | undefined = arkts.getDecl(typeAnnotation.part.name); if (!!decl && arkts.isTSTypeAliasDeclaration(decl)) { - return hasMemoAnnotation(decl) || hasMemoIntrinsicAnnotation(decl); + return hasMemoAnnotation(decl) || hasMemoIntrinsicAnnotation(decl) || decl.typeAnnotation ? findMemoFromTypeAnnotation(decl.typeAnnotation) : false; } } else if (arkts.isETSFunctionType(typeAnnotation)) { return hasMemoAnnotation(typeAnnotation) || hasMemoIntrinsicAnnotation(typeAnnotation); diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index 745305fec7d670c8b2d5d01166a9a8ce9b5d8c38..d5c9d3942751b25d255e5ea2440635c13d383f4d 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -41,6 +41,7 @@ import { ImportCollector } from '../common/import-collector'; import { DeclarationCollector } from '../common/declaration-collector'; import { PropertyCache } from './property-translators/utils'; import { isArkUICompatible, generateArkUICompatible } from './interop/interop'; +import { checkCustomDialogController, insertImportDeclaration, transformDeclaration } from './customdialog'; import { LogCollector } from '../common/log-collector'; export class CheckedTransformer extends AbstractVisitor { @@ -92,6 +93,24 @@ 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)) { @@ -102,7 +121,9 @@ export class CheckedTransformer extends AbstractVisitor { return this.visitEachChild(lambda); } const node = this.visitEachChild(beforeChildren); - if ( + if (this.isCustomDialogController()) { + return this.processCustomDialogController(node); + } else if ( arkts.isClassDeclaration(node) && this.scope.customComponents.length > 0 && isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) @@ -129,6 +150,8 @@ export class CheckedTransformer extends AbstractVisitor { LogCollector.getInstance().emitLogInfo(); } else if (arkts.isTSTypeAliasDeclaration(node)) { return structFactory.transformTSTypeAlias(node); + } else if (arkts.isBlockStatement(node)) { + return checkCustomDialogController(node); } return node; } diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index ac7ea9cf6e5e4843598deb773624338bd6e88601..10a9c2b524d6e5589a9d6de1e092348f9961b481 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -48,6 +48,7 @@ import { ENTRY_POINT_IMPORT_SOURCE_NAME, } from '../common/predefines'; import { generateInstantiateInterop } from './interop/interop'; +import { createCustomDialogMethod, isNewCustomDialogController, transformController } from './customdialog'; export interface ComponentTransformerOptions extends VisitorOptions { arkui?: string; @@ -77,6 +78,7 @@ export class ComponentTransformer extends AbstractVisitor { private hasLegacy: boolean = false; private legacyStructMap: Map = new Map(); private legacyCallMap: Map = new Map(); + private customDialogController: string = ''; constructor(options?: ComponentTransformerOptions) { const _options: ComponentTransformerOptions = options ?? {}; @@ -98,6 +100,7 @@ export class ComponentTransformer extends AbstractVisitor { this.hasLegacy = false; this.legacyStructMap = new Map(); this.legacyCallMap = new Map(); + this.customDialogController = ''; } enter(node: arkts.AstNode) { @@ -142,6 +145,9 @@ export class ComponentTransformer extends AbstractVisitor { CustomComponentNames.LAYOUT_CALLBACK ); } + if (this.isCustomDialog() && arkts.isClassProperty(node)) { + this.hasCustomDialogController(node); + } } exit(node: arkts.AstNode) { @@ -153,6 +159,38 @@ 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); @@ -270,6 +308,11 @@ export class ComponentTransformer extends AbstractVisitor { newDefinitionBody.push(entryFactory.createEntryLocalStorageInClass(entryWithStorage)); } } + if (!!scopeInfo.annotations.customdialog) { + const setDialogController = createCustomDialogMethod(this.customDialogController); + newDefinitionBody.push(setDialogController); + this.customDialogController = ''; + } const newDefinition: arkts.ClassDefinition = this.createNewDefinition( node, className, @@ -454,6 +497,9 @@ 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 && diff --git a/arkui-plugins/ui-plugins/customdialog.ts b/arkui-plugins/ui-plugins/customdialog.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a238ab053c2c1e80b9fb0eab0e7599cacb46ea2 --- /dev/null +++ b/arkui-plugins/ui-plugins/customdialog.ts @@ -0,0 +1,468 @@ +/* + * 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/regularProperty.ts b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index a059055f45225e927929530747f8fa778d777126..7960157cd39293f2316635b8cf304232b5a095c7 100644 --- a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -20,6 +20,7 @@ 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[] { @@ -29,9 +30,24 @@ 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 initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + 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]); + } if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); @@ -83,13 +99,13 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini return createSetter2(originalName, typeAnnotation, statement); } - generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { + generateInitializeStruct(newName: string, originalName: string, value: arkts.Expression): arkts.AstNode { const binaryItem = arkts.factory.createBinaryExpression( factory.createBlockStatementForOptionalExpression( arkts.factory.createIdentifier('initializers'), originalName ), - this.property.value ?? arkts.factory.createUndefinedLiteral(), + value ?? arkts.factory.createUndefinedLiteral(), arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING ); const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index 8a1cc6c61f295dea4d80218206ddc286be0d3fb7..0c8ca988d850d3077bea5d2e9fb570c770ffafb0 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -32,6 +32,10 @@ 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 BuilderLambdaNames { @@ -144,6 +148,7 @@ export type CustomComponentAnontations = { reusable?: arkts.AnnotationUsage; reusableV2?: arkts.AnnotationUsage; customLayout?: arkts.AnnotationUsage; + customdialog?: arkts.AnnotationUsage; }; type StructAnnoationInfo = { @@ -153,6 +158,7 @@ type StructAnnoationInfo = { isReusable: boolean; isReusableV2: boolean; isCustomLayout: boolean; + isCustomDialog: boolean; }; export function isCustomComponentAnnotation( @@ -199,9 +205,9 @@ export function collectCustomComponentScopeInfo( if (!isCustomComponentClassDecl) { let isCustomComponent: boolean = false; for (const anno of definition.annotations) { - const { isComponent, isComponentV2, isEntry, isReusable, isReusableV2, isCustomLayout } = + const { isComponent, isComponentV2, isEntry, isReusable, isReusableV2, isCustomLayout, isCustomDialog } = getAnnotationInfoForStruct(anno, shouldIgnoreDecl); - isCustomComponent ||= isComponent || isComponentV2; + isCustomComponent ||= isComponent || isComponentV2 || isCustomDialog; annotations = { ...annotations, ...(isComponent && !annotations?.component && { component: anno }), @@ -210,6 +216,7 @@ export function collectCustomComponentScopeInfo( ...(isReusable && !annotations?.reusable && { reusable: anno }), ...(isReusableV2 && !annotations?.reusableV2 && { reusableV2: anno }), ...(isCustomLayout && !annotations?.customLayout && { customLayout: anno }), + ...(isCustomDialog && !annotations?.reusable && { customdialog: anno }), }; } if (!isCustomComponent) { @@ -233,7 +240,8 @@ export function getAnnotationInfoForStruct( const isReusable = isCustomComponentAnnotation(anno, StructDecoratorNames.RESUABLE, shouldIgnoreDecl); const isReusableV2 = isCustomComponentAnnotation(anno, StructDecoratorNames.RESUABLE_V2, shouldIgnoreDecl); const isCustomLayout = isCustomComponentAnnotation(anno, StructDecoratorNames.CUSTOM_LAYOUT, shouldIgnoreDecl); - return { isComponent, isComponentV2, isEntry, isReusable, isReusableV2, isCustomLayout }; + const isCustomDialog = isCustomComponentAnnotation(anno, StructDecoratorNames.CUSTOMDIALOG, shouldIgnoreDecl); + return { isComponent, isComponentV2, isEntry, isReusable, isReusableV2, isCustomLayout, isCustomDialog }; } export function isComponentStruct(node: arkts.StructDeclaration, scopeInfo: CustomComponentInfo): boolean { diff --git a/koala-wrapper/src/arkts-api/visitor.ts b/koala-wrapper/src/arkts-api/visitor.ts index b2bca233671de1e6348a744fa6ff0085cdb79b99..b0a45fbda56a9a5f8d73833a7a64d9568876a392 100644 --- a/koala-wrapper/src/arkts-api/visitor.ts +++ b/koala-wrapper/src/arkts-api/visitor.ts @@ -109,12 +109,10 @@ export function visitEachChild(node: AstNode, visitor: Visitor): AstNode { function visitOuterExpression(node: AstNode, visitor: Visitor): AstNode { if (updated) { return node; - } - if (isBlockExpression(node)) { + } else if (isBlockExpression(node)) { updated = true; return factory.updateBlockExpression(node, nodesVisitor(node.statements, visitor)); - } - if (isCallExpression(node)) { + } else if (isCallExpression(node)) { updated = true; const call = factory.updateCallExpression( node, @@ -126,12 +124,10 @@ function visitOuterExpression(node: AstNode, visitor: Visitor): AstNode { call.setTralingBlock(nodeVisitor(node.trailingBlock, visitor)); } return call; - } - if (isArrowFunctionExpression(node)) { + } else if (isArrowFunctionExpression(node)) { updated = true; return factory.updateArrowFunction(node, nodeVisitor(node.scriptFunction, visitor)); - } - if (isAssignmentExpression(node)) { + } else if (isAssignmentExpression(node)) { updated = true; return factory.updateAssignmentExpression( node, @@ -139,8 +135,7 @@ function visitOuterExpression(node: AstNode, visitor: Visitor): AstNode { node.operatorType, nodeVisitor(node.right as Expression, visitor) ); - } - if (isETSNewClassInstanceExpression(node)) { + } else if (isETSNewClassInstanceExpression(node)) { updated = true; return factory.updateETSNewClassInstanceExpression( node,