From 0a600ed36c34f9606299fee8efbdcf93902f4a4b Mon Sep 17 00:00:00 2001 From: l00913061 Date: Sun, 3 Aug 2025 00:09:39 +0800 Subject: [PATCH] fileInterop Signed-off-by: l00913061 --- arkui-plugins/common/arkts-utils.ts | 17 +++ arkui-plugins/common/file-manager.ts | 81 ++++++++++++++ arkui-plugins/common/plugin-context.ts | 4 + arkui-plugins/common/predefines.ts | 8 +- arkui-plugins/common/program-visitor.ts | 70 ++++-------- .../ui-plugins/component-transformer.ts | 68 ------------ arkui-plugins/ui-plugins/interop/interop.ts | 105 ++++++------------ .../ui-plugins/interop/legacy-transformer.ts | 82 +++++--------- arkui-plugins/ui-plugins/interop/utils.ts | 46 +++++++- .../ui-plugins/struct-translators/factory.ts | 7 +- 10 files changed, 240 insertions(+), 248 deletions(-) create mode 100644 arkui-plugins/common/file-manager.ts diff --git a/arkui-plugins/common/arkts-utils.ts b/arkui-plugins/common/arkts-utils.ts index 1b01d9248..fea5fa9ef 100644 --- a/arkui-plugins/common/arkts-utils.ts +++ b/arkui-plugins/common/arkts-utils.ts @@ -16,6 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { DeclarationCollector } from './declaration-collector'; import { ARKUI_IMPORT_PREFIX_NAMES, DecoratorNames } from './predefines'; +import * as fs from 'fs'; /** * create and insert `import { as } from ` to the top of script's statements. @@ -174,3 +175,19 @@ export function forEachArgWithParam( const lastArg = args.at(lastIndex); callbackFn(lastArg, lastParam, maxLen - 1); } + +export function toUnixPath(path: string): string { + return path.replace(/\\/g, '/'); +} + +export function readFirstLineSync(filePath: string): string | null { + const fd = fs.openSync(filePath, 'r'); + const buffer = Buffer.alloc(256); + const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, 0); + fs.closeSync(fd); + + const content = buffer.toString('utf-8', 0, bytesRead); + const firstLine = content.split(/\r?\n/, 1)[0].trim(); + + return firstLine; +} \ No newline at end of file diff --git a/arkui-plugins/common/file-manager.ts b/arkui-plugins/common/file-manager.ts new file mode 100644 index 000000000..ec68bf872 --- /dev/null +++ b/arkui-plugins/common/file-manager.ts @@ -0,0 +1,81 @@ +/* + * 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 { LANGUAGE_VERSION } from './predefines'; +import { readFirstLineSync, toUnixPath } from './arkts-utils'; +import { BuildConfig, DependentModuleConfig } from './plugin-context'; + + +export class FileManager { + private static instance: FileManager | undefined = undefined; + static arkTSModuleMap: Map = new Map(); + static staticApiPath: Set = new Set(); + static dynamicApiPath: Set = new Set(); + static buildConfig: BuildConfig; + private constructor() { } + + static setInstance(instance: FileManager): void { + if (!instance) { + throw Error('fileManager is undefined!'); + } + FileManager.instance = instance; + } + + static getInstance(): FileManager { + if (!FileManager.instance) { + throw Error('fileManager not exist.'); + } + return FileManager.instance; + } + + private static isFirstLineUseStatic(filePath: string): boolean { + const firstLine = readFirstLineSync(filePath); + return firstLine === "'use static'"; + } + + getLanguageVersionByFilePath(filePath: string): string { + const path = toUnixPath(filePath); + for (const apiPath of FileManager.staticApiPath) { + if (path.startsWith(apiPath)) { + return LANGUAGE_VERSION.ARKTS_1_2; + } + } + for (const apiPath of FileManager.dynamicApiPath) { + if (path.startsWith(apiPath)) { + return LANGUAGE_VERSION.ARKTS_1_1; + } + } + if (FileManager.buildConfig.compileFiles?.includes(filePath)) { + return LANGUAGE_VERSION.ARKTS_1_2; + } + for (const [pkgName, moduleInfo] of FileManager.arkTSModuleMap) { + if (!path.startsWith(moduleInfo.modulePath)) { + continue; + } + if (moduleInfo.language !== LANGUAGE_VERSION.ARKTS_HYBRID) { + return moduleInfo.language; + } + /** + * when process hybrid hsp or har we can't get info of 1.1, + * only by module decl-fileinfo.json or `'use static'` + */ + if (FileManager.isFirstLineUseStatic(filePath)) { + return LANGUAGE_VERSION.ARKTS_1_2; + } + } + return LANGUAGE_VERSION.ARKTS_1_1; + } +} diff --git a/arkui-plugins/common/plugin-context.ts b/arkui-plugins/common/plugin-context.ts index f661350a0..f5abb7559 100644 --- a/arkui-plugins/common/plugin-context.ts +++ b/arkui-plugins/common/plugin-context.ts @@ -124,6 +124,10 @@ export interface ProjectConfig { frameworkMode?: string; } +export interface BuildConfig { + compileFiles: string[]; +} + export type PluginHandlerFunction = () => void; export type PluginHandlerObject = { diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index de04875ea..a36b1ece8 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -387,4 +387,10 @@ export enum GetSetTypes { export enum GenSymPrefix { INTRINSIC = 'gensym%%', UI = 'gensym__' -} \ No newline at end of file +} + +export enum LANGUAGE_VERSION { + ARKTS_1_2 = '1.2', + ARKTS_1_1 = '1.1', + ARKTS_HYBRID = 'hybrid', +}; \ No newline at end of file diff --git a/arkui-plugins/common/program-visitor.ts b/arkui-plugins/common/program-visitor.ts index 55ac1aad4..ea60e260e 100644 --- a/arkui-plugins/common/program-visitor.ts +++ b/arkui-plugins/common/program-visitor.ts @@ -21,6 +21,8 @@ import { InteroperAbilityNames } from '../ui-plugins/interop/predefines'; import { PluginContext } from './plugin-context'; import { LegacyTransformer } from '../ui-plugins/interop/legacy-transformer'; import { ComponentTransformer } from '../ui-plugins/component-transformer'; +import { FileManager } from './file-manager'; +import { LANGUAGE_VERSION } from './predefines'; export interface ProgramVisitorOptions extends VisitorOptions { pluginName: string; @@ -59,10 +61,6 @@ function flattenVisitorsInHooks( ]; } -export interface StructMap { - [key: string]: string; -} - export class ProgramVisitor extends AbstractVisitor { private readonly pluginName: string; private readonly state: arkts.Es2pandaContextState; @@ -71,8 +69,6 @@ export class ProgramVisitor extends AbstractVisitor { private readonly hooks?: ProgramHooks; private filenames: Map; private pluginContext?: PluginContext; - private legacyModuleList: string[] = []; - private legacyStructMap: Map; constructor(options: ProgramVisitorOptions) { super(options); @@ -83,33 +79,12 @@ export class ProgramVisitor extends AbstractVisitor { this.hooks = options.hooks; this.filenames = new Map(); this.pluginContext = options.pluginContext; - this.legacyModuleList = []; - this.legacyStructMap = new Map(); + FileManager.setInstance(this.pluginContext?.fileManager); } reset(): void { super.reset(); this.filenames = new Map(); - this.legacyStructMap = new Map(); - this.legacyModuleList = []; - } - - private getLegacyModule(): void { - const moduleList = this.pluginContext?.getProjectConfig()?.dependentModuleList; - if (moduleList === undefined) { - return; - } - for (const module of moduleList) { - const language = module.language; - const moduleName = module.moduleName; - if (language !== InteroperAbilityNames.ARKTS_1_1) { - continue; - } - if (!this.legacyStructMap.has(moduleName)) { - this.legacyStructMap.set(moduleName, {}); - this.legacyModuleList.push(moduleName); - } - } } private dumpExternalSource( @@ -128,15 +103,12 @@ export class ProgramVisitor extends AbstractVisitor { ); } - private visitLegacyInExternalSource(currProgram: arkts.Program, name: string): void { - if (this.state === arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED) { - const structList = this.visitorLegacy(currProgram.astNode, currProgram, name); - const moduleName = name.split('/')[0]; - const structMap = this.legacyStructMap.get(moduleName)!; - for (const struct of structList) { - structMap[struct] = name; - } - } + private visitLegacyInExternalSource(program: arkts.Program, externalSourceName: string): void { + const transformer = new LegacyTransformer(); + transformer.isExternal = !!externalSourceName; + transformer.externalSourceName = externalSourceName; + transformer.program = program; + transformer.visitor(program.astNode); } private visitNonLegacyInExternalSource( @@ -167,13 +139,20 @@ export class ProgramVisitor extends AbstractVisitor { } } + private isLegacyFile(path: string): boolean { + const fileManager = FileManager.getInstance(); + if (fileManager.getLanguageVersionByFilePath(path) === LANGUAGE_VERSION.ARKTS_1_1) { + return true; + } + return false; + } + private visitExternalSources( program: arkts.Program, programQueue: arkts.Program[] ): void { const visited = new Set(); const queue: arkts.Program[] = programQueue; - this.getLegacyModule(); while (queue.length > 0) { const currProgram = queue.shift()!; if (visited.has(currProgram.peer) || currProgram.isASTLowered()) { @@ -182,7 +161,8 @@ export class ProgramVisitor extends AbstractVisitor { if (currProgram.peer !== program.peer) { const name: string = this.filenames.get(currProgram.peer)!; const cachePath: string | undefined = this.pluginContext?.getProjectConfig()?.cachePath; - if (this.legacyModuleList && matchPrefix(this.legacyModuleList, name)) { + if (this.state === arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED && this.pluginName === 'uiTransform' && + this.isLegacyFile(currProgram.absName)) { this.visitLegacyInExternalSource(currProgram, name); } else { this.visitNonLegacyInExternalSource(program, currProgram, name, cachePath); @@ -254,9 +234,6 @@ export class ProgramVisitor extends AbstractVisitor { this.preVisitor(hook, node, program, externalSourceName); for (const transformer of this.visitors) { - if (this.legacyStructMap.size > 0 && transformer instanceof ComponentTransformer) { - transformer.registerMap(this.legacyStructMap); - } this.visitTransformer(transformer, script, externalSourceName, program); transformer.reset(); arkts.setAllParents(script); @@ -278,15 +255,6 @@ export class ProgramVisitor extends AbstractVisitor { return script; } - private visitorLegacy(node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string): string[] { - const transformer = new LegacyTransformer(); - transformer.isExternal = !!externalSourceName; - transformer.externalSourceName = externalSourceName; - transformer.program = program; - transformer.visitor(node); - const structList = transformer.getList(); - return structList; - } private visitTransformer( transformer: AbstractVisitor, diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index a4c436972..0e40f7ebb 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -44,7 +44,6 @@ import { factory as entryFactory } from './entry-translators/factory'; import { hasDecoratorName, findDecoratorInfos } from './property-translators/utils'; import { factory } from './ui-factory'; import { factory as propertyFactory } from './property-translators/factory'; -import { StructMap } from '../common/program-visitor'; import { CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, DecoratorIntrinsicNames, @@ -54,7 +53,6 @@ import { NavigationNames, EntryWrapperNames, } from '../common/predefines'; -import { generateInstantiateInterop } from './interop/interop'; export interface ComponentTransformerOptions extends VisitorOptions { arkui?: string; @@ -84,9 +82,6 @@ export class ComponentTransformer extends AbstractVisitor { private isPageLifeCycleImported: boolean = false; private isLayoutCallbackImported: boolean = false; private shouldAddLinkIntrinsic: boolean = false; - private hasLegacy: boolean = false; - private legacyStructMap: Map = new Map(); - private legacyCallMap: Map = new Map(); private projectConfig: ProjectConfig | undefined; private entryRouteName: string | undefined; private componentType: ComponentType = { @@ -115,9 +110,6 @@ export class ComponentTransformer extends AbstractVisitor { this.isPageLifeCycleImported = false; this.isLayoutCallbackImported = false; this.shouldAddLinkIntrinsic = false; - this.hasLegacy = false; - this.legacyStructMap = new Map(); - this.legacyCallMap = new Map(); this.componentType = { hasComponent: false, hasComponentV2: false, @@ -485,56 +477,6 @@ export class ComponentTransformer extends AbstractVisitor { return [originMember]; } - registerMap(map: Map): void { - this.legacyStructMap = map; - this.hasLegacy = true; - } - - processInteropImport(node: arkts.ETSImportDeclaration): void { - const source = node.source?.str!; - const specifiers = node.specifiers as arkts.ImportSpecifier[]; - if (this.legacyStructMap.has(source)) { - const structMap = this.legacyStructMap.get(source); - if (!structMap) { - return; - } - for (const specifier of specifiers) { - const name = (specifier as arkts.ImportSpecifier)!.local!.name; - if (structMap[name]) { - this.legacyCallMap.set(name, structMap[name]); - } - } - } - } - - processInteropCall(node: arkts.CallExpression): arkts.CallExpression { - const ident = node.expression; - if (!(ident instanceof arkts.Identifier)) { - return node; - } - const className = ident.name; - const trailingBlock = node.trailingBlock; - const content = trailingBlock ? arkts.factory.createArrowFunction( - factory.createScriptFunction({ - body: trailingBlock, - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - }) - ) : undefined; - if (this.legacyCallMap.has(className)) { - const path = this.legacyCallMap.get(className)!; - const args = node.arguments; - const context: InteropContext = { - className: className, - path: path, - arguments: args && args.length === 1 && args[0] instanceof arkts.ObjectExpression ? args[0] : undefined, - content: content - }; - return generateInstantiateInterop(context); - } - return node; - } - visitor(node: arkts.AstNode): arkts.AstNode { this.enter(node); const newNode = this.visitEachChild(node); @@ -563,16 +505,6 @@ export class ComponentTransformer extends AbstractVisitor { ) { return factory.updateCustomDialogOptionsInterface(newNode); } - // process interop code - if (!this.hasLegacy) { - return newNode; - } - if (arkts.isETSImportDeclaration(newNode)) { - this.processInteropImport(newNode); - } - if (arkts.isCallExpression(newNode)) { - return this.processInteropCall(newNode); - } return newNode; } } diff --git a/arkui-plugins/ui-plugins/interop/interop.ts b/arkui-plugins/ui-plugins/interop/interop.ts index 8da4bc6d5..bd481e957 100644 --- a/arkui-plugins/ui-plugins/interop/interop.ts +++ b/arkui-plugins/ui-plugins/interop/interop.ts @@ -29,8 +29,6 @@ import { createELMTID, createInitReturn } from './utils'; -import { ImportCollector } from '../../common/import-collector'; -import { factory as uiFactory } from '../ui-factory'; import { DecoratorNames } from '../../common/predefines'; import { hasDecorator } from '../property-translators/utils'; @@ -329,12 +327,8 @@ function updateArguments(context: InteropContext, name: string): arkts.ObjectExp ); } -function generateVarMap(context: InteropContext, node: arkts.Identifier): Map { +function generateVarMap(context: InteropContext, decl: arkts.ClassDefinition): Map { let needBuilderParam = !!context.content; - const decl = arkts.getDecl(node); - if (!(decl instanceof arkts.ClassDefinition)) { - throw Error("can't find legacy class declaration"); - } const result = new Map(); const definition = decl; const body = definition.body; @@ -351,87 +345,58 @@ function generateVarMap(context: InteropContext, node: arkts.Identifier): Map.instantiate_Interop. - */ -export function generateInstantiateInterop(context: InteropContext): arkts.CallExpression { - return arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - arkts.factory.createIdentifier(context.className), - arkts.factory.createIdentifier('instantiate_Interop'), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - undefined, - generateStructInfo(context) - ); -} -/** - * - * @param node - * @returns {boolean} Checks if a given CallExpression represents a call to .instantiate_Interop. - */ -export function isArkUICompatible(node: arkts.AstNode): boolean { - if (node instanceof arkts.CallExpression && node.expression instanceof arkts.MemberExpression && - node.expression.property instanceof arkts.Identifier && - node.expression.property.name === 'instantiate_Interop') { - ImportCollector.getInstance().collectSource(InteroperAbilityNames.ARKUICOMPATIBLE, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(InteroperAbilityNames.ARKUICOMPATIBLE); - ImportCollector.getInstance().collectSource(InteroperAbilityNames.GETCOMPATIBLESTATE, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(InteroperAbilityNames.GETCOMPATIBLESTATE); - ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER); - return true; +export function processArgumens(arg: arkts.Expression): arkts.ObjectExpression { + if (!arkts.isObjectExpression(arg)) { + throw new Error('Cannot find arguments for InteropComponent'); } - return false; + const properties = arg.properties.map((property: arkts.Property) => { + const key = property.key; + if (arkts.isIdentifier(key) && key.name.startsWith('__backing_')) { + return arkts.updateProperty( + property, + arkts.updateIdentifier( + key, + key.name.slice('__backing_'.length) + ), + property.value + ); + } + return property; + }); + return arkts.updateObjectExpression( + arg, + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + properties, + false + ) } - /** * * @param node * @returns After Checked, transform instantiate_Interop -> ArkUICompatible */ export function generateArkUICompatible(node: arkts.CallExpression): arkts.CallExpression { - const classInterop = (node.expression as arkts.MemberExpression).object as arkts.Identifier; + const classInterop = (node.expression as arkts.MemberExpression).object as arkts.identifier; const className = classInterop.name; + + const decl = arkts.getDecl(classInterop); + if (!(decl instanceof arkts.ClassDefinition)) { + throw Error("can't find legacy class declaration"); + } + const filePath = arkts.getProgramFromAstNode(decl).moduleName; const args = node.arguments; - const path = (args[0] as arkts.StringLiteral).str; - const line = args[1] instanceof arkts.UndefinedLiteral ? undefined : (args[1] as arkts.NumberLiteral).value; - const col = args[2] instanceof arkts.UndefinedLiteral ? undefined : (args[2] as arkts.NumberLiteral).value; - const options = args[3] instanceof arkts.UndefinedLiteral ? undefined : args[3] as arkts.ObjectExpression; - const content = args[4] instanceof arkts.UndefinedLiteral ? undefined : args[4] as arkts.ArrowFunctionExpression; + const options = arkts.isUndefinedLiteral(args[2]) ? undefined : processArgumens(args[2]); + const content = arkts.isUndefinedLiteral(args[4]) ? undefined : args[4]; const context: InteropContext = { className: className, - path: path, - line: line, - col: col, + path: filePath, arguments: options, content: content, }; - const varMap: Map = generateVarMap(context, classInterop); + const varMap: Map = generateVarMap(context, decl); const updateProp: arkts.Property[] = []; const initializer = createInitializer(context, varMap, updateProp); const updater = createUpdater(updateProp); diff --git a/arkui-plugins/ui-plugins/interop/legacy-transformer.ts b/arkui-plugins/ui-plugins/interop/legacy-transformer.ts index 366678e19..4695d7e5e 100644 --- a/arkui-plugins/ui-plugins/interop/legacy-transformer.ts +++ b/arkui-plugins/ui-plugins/interop/legacy-transformer.ts @@ -49,15 +49,10 @@ export class LegacyTransformer extends AbstractVisitor { // TODO: check reset reset(): void { super.reset(); - this.structList = []; this.componentInterfaceCollection = []; this.scopeInfos = []; } - getList(): string[] { - return this.structList; - } - createParam(name: string, type: string): arkts.ETSParameterExpression { return arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier( @@ -72,38 +67,6 @@ export class LegacyTransformer extends AbstractVisitor { ); } - createInteropMethod(name: string): arkts.MethodDefinition { - const path = this.createParam('path', 'string'); - const line = this.createParam('line', 'number'); - line.setOptional(true); - const col = this.createParam('col', 'number'); - col.setOptional(true); - const options = this.createParam('options', getCustomComponentOptionsName(name)); - options.setOptional(true); - const trailingBlock = this.createParam('trailingBlock', 'Object'); - trailingBlock.setOptional(true); - - const script = arkts.factory.createScriptFunction( - arkts.factory.createBlock([]), - arkts.FunctionSignature.createFunctionSignature( - undefined, - [path, line, col, options, trailingBlock], - arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), - false - ), - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC - ); - - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, - arkts.factory.createIdentifier('instantiate_Interop'), - script, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, - false - ); - } - generateMember(map: Map): arkts.ClassProperty[] { const properties: arkts.ClassProperty[] = []; @@ -146,17 +109,15 @@ export class LegacyTransformer extends AbstractVisitor { this.structList.push(ident.name); } - const instantiate_Interop: arkts.MethodDefinition = this.createInteropMethod(ident.name); - const newDefinition = arkts.factory.updateClassDefinition( definition, definition.ident, definition.typeParams, - definition.superTypeParams, + undefined, definition.implements, undefined, - definition.super, - [...definition.body, instantiate_Interop], + undefined, + ...definition.body, definition.modifiers, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE ); @@ -244,8 +205,9 @@ export class LegacyTransformer extends AbstractVisitor { } enter(node: arkts.AstNode): void { - if (arkts.isStructDeclaration(node) && !!node.definition.ident) { - const scopeInfo: ScopeInfo = { name: node.definition.ident.name }; + if ((arkts.isStructDeclaration(node) || arkts.isClassDeclaration(node)) && !!node.definition.ident) { + const isComponent = node.definition.annotations.some(annotation => annotation.expr instanceof arkts.Identifier && annotation.expr.name === 'Component'); + const scopeInfo: ScopeInfo = { name: node.definition.ident.name, isComponent: isComponent}; this.scopeInfos.push(scopeInfo); } } @@ -317,25 +279,37 @@ export class LegacyTransformer extends AbstractVisitor { if (arkts.isEtsScript(newNode)) { return this.processEtsScript(newNode); } - if (arkts.isStructDeclaration(newNode)) { + if (arkts.isStructDeclaration(newNode) || arkts.isClassDeclaration(newNode)) { const definition = newNode.definition!; const annotations = definition.annotations; - if (annotations.some(annotation => annotation instanceof arkts.Identifier && annotation.name === 'Component')) { - return newNode; + if (annotations.some(annotation => annotation.expr instanceof arkts.Identifier && annotation.expr.name === 'Component')) { + const updateNode = this.processComponent(newNode); + this.exit(newNode); + return updateNode; } - const className = newNode.definition?.ident?.name!; - const memberMap = this.collectComponentMembers(newNode as arkts.StructDeclaration, className); - this.componentInterfaceCollection.push(this.generateComponentInterface(className, node.modifiers, memberMap)); - const updateNode = this.processComponent(newNode); - this.exit(newNode); - return updateNode; + return newNode; } - if (this.scopeInfos.length > 0 && arkts.isMethodDefinition(newNode)) { + if (this.scopeInfos.length > 0 && this.scopeInfos[this.scopeInfos.length - 1].isComponent === true && + arkts.isMethodDefinition(newNode)) { const kind = newNode.kind; if (kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR) { const updateNode = this.processConstructor(newNode); return updateNode; } + if (newNode.name.name === 'build') { + return arkts.factory.updateMethodDefinition( + newNode, + newNode.kind, + newNode.name, + factory.createScriptFunction( + { + returnTypeAnnotation: arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID) + } + ), + newNode.modifiers, + false + ); + } } if (arkts.isVariableDeclarator(newNode)) { return this.handleWrappedBuilder(newNode); diff --git a/arkui-plugins/ui-plugins/interop/utils.ts b/arkui-plugins/ui-plugins/interop/utils.ts index 8ce38fe30..7c6c08c5d 100644 --- a/arkui-plugins/ui-plugins/interop/utils.ts +++ b/arkui-plugins/ui-plugins/interop/utils.ts @@ -16,7 +16,11 @@ import * as arkts from '@koalaui/libarkts'; -import { ESValueMethodNames, InteroperAbilityNames } from './predefines'; +import { BuilderMethodNames, ESValueMethodNames, InteroperAbilityNames } from './predefines'; +import { LANGUAGE_VERSION } from '../../common/predefines'; +import { FileManager } from '../../common/file-manager'; +import { BuilderLambdaNames } from '../utils'; +import { ImportCollector } from '../../common/import-collector'; /** @@ -221,3 +225,43 @@ export function createGlobal(): arkts.Statement { )] ); } + + +export function isInstantiateImpl(node: arkts.MemberExpression): boolean { + const property = node.property; + if (arkts.isIdentifier(property) && property.name === BuilderLambdaNames.TRANSFORM_METHOD_NAME) { + return true; + } + return false; +} + +export function isArkTS1_1(node: arkts.MemberExpression): boolean { + const struct = node.object; + const decl = arkts.getDecl(struct); + if (!decl) { + return false; + } + const filePath = arkts.getProgramFromAstNode(decl).absName; + const fileManager = FileManager.getInstance(); + if (fileManager.getLanguageVersionByFilePath(filePath) === LANGUAGE_VERSION.ARKTS_1_1) { + return true; + } + return false; +} + +export function isInteropComponent(node: arkts.CallExpression): boolean { + if ( + arkts.isMemberExpression(node.expression) && + isInstantiateImpl(node.expression) && + isArkTS1_1(node.expression) + ) { + ImportCollector.getInstance().collectSource(InteroperAbilityNames.ARKUICOMPATIBLE, InteroperAbilityNames.INTEROP); + ImportCollector.getInstance().collectImport(InteroperAbilityNames.ARKUICOMPATIBLE); + ImportCollector.getInstance().collectSource(InteroperAbilityNames.GETCOMPATIBLESTATE, InteroperAbilityNames.INTEROP); + ImportCollector.getInstance().collectImport(InteroperAbilityNames.GETCOMPATIBLESTATE); + ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER, InteroperAbilityNames.INTEROP); + ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER); + return true; + } + return false; +} diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index d4fd4e5d1..4225fea4f 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -82,9 +82,10 @@ import { collectMemoableInfoInFunctionReturnType, collectScriptFunctionReturnTypeFromInfo, } from '../../collectors/memo-collectors/utils'; -import { generateArkUICompatible, isArkUICompatible } from '../interop/interop'; +import { generateArkUICompatible } from '../interop/interop'; import { GenSymGenerator } from '../../common/gensym-generator'; import { MethodTranslator } from 'ui-plugins/property-translators/base'; +import { isInteropComponent } from '../interop/utils'; export class factory { /** @@ -1100,8 +1101,8 @@ export class factory { if (arkts.isCallExpression(node) && isForEachCall(node)) { return this.transformCallArguments(node); } - if (isArkUICompatible(node)) { - return generateArkUICompatible(node as arkts.CallExpression); + if (arkts.isCallExpression(node) && isInteropComponent(node)) { + return generateArkUICompatible(node); } return node; } -- Gitee