diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index 6ad6317975430e3b1394666130bf7808f57e28cd..97b02c9158b12830e2fd72367cadc2b624b91cd2 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -209,6 +209,8 @@ export class CheckedTransformer extends AbstractVisitor { isSpecificNewClass(node, CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) ) { return structFactory.transformCustomDialogController(node); + } else if (arkts.isClassProperty(node)) { + structFactory.checkObservedPropertyV1InteropV2(node); } if (arkts.isEtsScript(node) && ImportCollector.getInstance().importInfos.length > 0) { diff --git a/arkui-plugins/ui-plugins/interop/initstatevar.ts b/arkui-plugins/ui-plugins/interop/initstatevar.ts index 1f43c179e015d9c039e977070a2f1c661c4c057b..c74c7e3bbdb6dd357f73367e99dedc16678cb6d2 100644 --- a/arkui-plugins/ui-plugins/interop/initstatevar.ts +++ b/arkui-plugins/ui-plugins/interop/initstatevar.ts @@ -23,15 +23,14 @@ import { hasDecorator } from '../property-translators/utils'; import { DecoratorNames } from '../../common/predefines'; -export function initialArgs(args: arkts.ObjectExpression, varMap: Map, updateProp: arkts.Property[]): arkts.Statement[] { +export function initialArgs(args: arkts.ObjectExpression, varMap: Map, + updateProp: arkts.Property[], node: arkts.CallExpression, isV2: boolean): arkts.Statement[] { const result: arkts.Statement[] = []; const proxySet = new Set(); - - for (const property of args.properties) { if (!(property instanceof arkts.Property)) { continue; - } + } const key = property.key; const value = property.value!; if (!(key instanceof arkts.Identifier)) { @@ -40,8 +39,9 @@ export function initialArgs(args: arkts.ObjectExpression, varMap: Map valueType = getPropertyType(annotations)); + isComponentV2forParent = valueProperty.parent?.annotations.some( + annotation => annotation.expr instanceof arkts.Identifier && annotation.expr.name === 'ComponentV2'); + } + if (keyProperty !== undefined) { + keyProperty.annotations.some((annotations) => ketType = getPropertyType(annotations)); + } + if (isV2) { + if (!isComponentV2forParent) { + let errorMessage = `The '${valueType}' property '${valueName}' cannot be assigned to the ${ketType} property ${keyName} when interop`; + const diagnosticKind = arkts.DiagnosticKind.create(errorMessage, arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_ERROR); + arkts.Diagnostic.logDiagnostic(diagnosticKind, arkts.getStartPosition(node)); + } + } else { + if (isComponentV2forParent) { + if (keyProperty.annotations && keyProperty.annotations.length !== 0) { + let errorMessage = `The '${valueType}' property '${valueName}' cannot be assigned to the ${ketType} property ${keyName} when interop`; + const diagnosticKind = arkts.DiagnosticKind.create(errorMessage, arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_ERROR); + arkts.Diagnostic.logDiagnostic(diagnosticKind, arkts.getStartPosition(node)); + } + } + } +} + +function getPropertyType(anno: arkts.AnnotationUsage): string { + let propertyType = 'regular'; + if (!!anno.expr && arkts.isIdentifier(anno.expr)) { + propertyType = anno.expr.name; + } + if (propertyType !== 'regular' && propertyType !== '') { + return '@' + propertyType; + } else { + return 'regular'; + } +} + export function createVariableLet(varName: string, expression: arkts.AstNode): arkts.VariableDeclaration { return arkts.factory.createVariableDeclaration( arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, diff --git a/arkui-plugins/ui-plugins/interop/interop.ts b/arkui-plugins/ui-plugins/interop/interop.ts index 5544444107e055b8b6186686a3fb034159bef282..a6a18ff99501c3504490f77f7b0edfc53c376fba 100644 --- a/arkui-plugins/ui-plugins/interop/interop.ts +++ b/arkui-plugins/ui-plugins/interop/interop.ts @@ -21,12 +21,12 @@ import { getCustomComponentOptionsName } from '../utils'; import { InteropContext } from '../component-transformer'; import { createVariableLet, initialArgs} from './initstatevar'; import { - getPropertyESValue, - getWrapValue, - setPropertyESValue, - createEmptyESValue, - createGlobal, - createELMTID, + getPropertyESValue, + getWrapValue, + setPropertyESValue, + createEmptyESValue, + createGlobal, + createELMTID, createInitReturn } from './utils'; import { ImportCollector } from '../../common/import-collector'; @@ -122,7 +122,7 @@ function newComponent(className: string): arkts.Statement { arkts.factory.createUndefinedLiteral(), generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.PARAM)), arkts.factory.createUndefinedLiteral(), - generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID)), + generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID)), arkts.factory.createTSAsExpression( arkts.factory.createArrowFunction( arkts.factory.createScriptFunction( @@ -174,7 +174,7 @@ function createComponent(className: string): arkts.Statement[] { function createWrapperBlock(context: InteropContext, varMap: Map, - updateProp: arkts.Property[]): arkts.BlockStatement { + updateProp: arkts.Property[], node: arkts.CallExpression, isV2: boolean): arkts.BlockStatement { const className: string = context.className; const path: string = context.path; const args: arkts.ObjectExpression | undefined = context.arguments; @@ -186,7 +186,7 @@ function createWrapperBlock(context: InteropContext, varMap: Map, - updateProp: arkts.Property[]): arkts.ArrowFunctionExpression { - const block = createWrapperBlock(context, varMap, updateProp); + updateProp: arkts.Property[], node: arkts.CallExpression, isV2: boolean): arkts.ArrowFunctionExpression { + const block = createWrapperBlock(context, varMap, updateProp, node, isV2); return arkts.factory.createArrowFunction( arkts.factory.createScriptFunction( block, @@ -432,10 +432,15 @@ export function generateArkUICompatible(node: arkts.CallExpression): arkts.CallE arguments: options, content: content, }; - + const decl = arkts.getDecl(classInterop); + if (!(decl instanceof arkts.ClassDefinition)) { + throw Error("can't find legacy class declaration"); + } const varMap: Map = generateVarMap(context, classInterop); const updateProp: arkts.Property[] = []; - const initializer = createInitializer(context, varMap, updateProp); + const isComponentV2 = decl.annotations.some( + annotation => annotation.expr instanceof arkts.Identifier && annotation.expr.name === 'ComponentV2'); + const initializer = createInitializer(context, varMap, updateProp, node, isComponentV2); const updater = createUpdater(updateProp); const result = arkts.factory.updateCallExpression( node, @@ -449,4 +454,74 @@ export function generateArkUICompatible(node: arkts.CallExpression): arkts.CallE ); arkts.NodeCache.getInstance().collect(result); return result; +} + +export function checkObservedPropertyV1InteropV2(node: arkts.ClassProperty): void { + if (node.annotations && node.annotations.length !== 0) { + let hasObserved = getHasAnnotationObserved(node, 'Observed'); + let hasObservedV2 = getHasAnnotationObserved(node, 'ObservedV2'); + if (hasObservedV2) { + let v1DecoratorList: string[] = [DecoratorNames.STATE, DecoratorNames.PROP_REF, DecoratorNames.LINK, DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, DecoratorNames.STORAGE_LINK, DecoratorNames.STORAGE_PROP_REF, DecoratorNames.LOCAL_STORAGE_LINK]; + let hasV1DecoratorInProperty = node.annotations.some( + annotation => annotation.expr instanceof arkts.Identifier && v1DecoratorList.includes(annotation.expr.name)); + if (hasV1DecoratorInProperty) { + let decoratorType = ''; + node.annotations.some( + annotation => decoratorType = getDecoratorType(annotation)); + let errorMessage = `The type of the '${decoratorType}' property can not be a class decorated with '@ObservedV2' when interop`; + const diagnosticKind = arkts.DiagnosticKind.create(errorMessage, arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_ERROR); + arkts.Diagnostic.logDiagnostic(diagnosticKind, arkts.getStartPosition(node)); + } + } + if (hasObserved) { + let v2DecoratorList: string[] = [DecoratorNames.LOCAL, DecoratorNames.PROVIDER, DecoratorNames.CONSUMER, DecoratorNames.PARAM, + DecoratorNames.EVENT]; + let hasV2DecoratorInProperty = node.annotations.some( + annotation => annotation.expr instanceof arkts.Identifier && v2DecoratorList.includes(annotation.expr.name)); + if (hasV2DecoratorInProperty) { + let decoratorType = ''; + node.annotations.some( + annotation => decoratorType = getDecoratorType(annotation)); + let errorMessage = `The type of the '${decoratorType}' property can not be a class decorated with '@Observed' when interop`; + const diagnosticKind = arkts.DiagnosticKind.create(errorMessage, arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_ERROR); + arkts.Diagnostic.logDiagnostic(diagnosticKind, arkts.getStartPosition(node)); + } + } + } +} + +function getDecoratorType(annotation: arkts.AnnotationUsage): string { + let propertyType = ''; + if (!!annotation.expr && arkts.isIdentifier(annotation.expr)) { + propertyType = '@' + annotation.expr.name; + } + return propertyType; +} + +function getHasAnnotationObserved(node: arkts.ClassProperty, annotationName: string): boolean { + let hasAnnotation = false; + let typeIdentifiers = []; + if (node.typeAnnotation && arkts.isETSTypeReference(node.typeAnnotation) && + node.typeAnnotation.part && arkts.isETSTypeReferencePart(node.typeAnnotation.part)) { + typeIdentifiers.push(node.typeAnnotation.part.name); + } else if (node.typeAnnotation && arkts.isETSUnionType(node.typeAnnotation)) { + node.typeAnnotation.types.forEach(item => { + if (item && arkts.isETSTypeReference(item) && item.part && arkts.isETSTypeReferencePart(item.part)) { + typeIdentifiers.push(item.part.name); + } + }); + } + typeIdentifiers.forEach(type => { + let typeDecl = arkts.getDecl(type); + let hasAnnotationItem = false; + if (typeDecl && typeDecl.annotations) { + hasAnnotationItem = typeDecl.annotations.some( + annotation => annotation.expr instanceof arkts.Identifier && annotation.expr.name === annotationName); + if (hasAnnotationItem) { + hasAnnotation = hasAnnotationItem; + } + } + }); + return hasAnnotation; } \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index f330329c3d6f3cde02b836c54eb0e7a8258d6947..dab17cb31247939ad5c6a610e6ee89f69a0d81bc 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -76,7 +76,7 @@ import { } from '../../common/predefines'; import { ObservedTranslator } from '../property-translators/index'; import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; -import { generateArkUICompatible, isArkUICompatible } from '../interop/interop'; +import { generateArkUICompatible, isArkUICompatible, checkObservedPropertyV1InteropV2 } from '../interop/interop'; import { GenSymGenerator } from '../../common/gensym-generator'; import { MethodTranslator } from '../property-translators/base'; import { MonitorCache } from '../property-translators/cache/monitorCache'; @@ -681,14 +681,14 @@ export class factory { static createSetControllerElements(controller: string): arkts.AstNode[] { return controller.length !== 0 ? [ - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(backingField(controller)), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - arkts.factory.createIdentifier(CustomDialogNames.CONTROLLER) - ) - ), - ] + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(backingField(controller)), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + arkts.factory.createIdentifier(CustomDialogNames.CONTROLLER) + ) + ), + ] : []; } @@ -707,8 +707,8 @@ export class factory { ) { const resourceId: number = projectConfig.moduleType === ModuleType.HAR || - fromOtherModule || - !resourceInfo.resourcesList[resourceData[0]] + fromOtherModule || + !resourceInfo.resourcesList[resourceData[0]] ? -1 : resourceInfo.resourcesList[resourceData[0]].get(resourceData[1])![resourceData[2]]; return factory.generateTransformedResourceCall( @@ -1281,4 +1281,8 @@ export class factory { ]; return arkts.factory.createBlockExpression(statements); } + + static checkObservedPropertyV1InteropV2(node: arkts.ClassProperty): void { + checkObservedPropertyV1InteropV2(node); + } }