From 4751c03673731b005cc5abf8e7346f7fb65abab4 Mon Sep 17 00:00:00 2001 From: Jiakai Shi Date: Fri, 27 Jun 2025 10:26:33 +0800 Subject: [PATCH] ui-plugin collector Signed-off-by: Jiakai Shi Change-Id: I1ccfa17e673abc085a70dc23d60de82eded0c26d --- .../memo-collectors/function-collector.ts | 28 +- .../collectors/memo-collectors/utils.ts | 117 ++++--- .../ui-collectors/call-record-collector.ts | 106 ++++++ .../collectors/ui-collectors/factory.ts | 163 +++++++++ .../ui-collectors/global-class-collector.ts | 58 ++++ .../ui-collectors/normal-class-collector.ts | 143 ++++++++ .../normal-interface-collector.ts | 73 ++++ .../ui-collectors/records/annotations/base.ts | 132 +++++++ .../records/annotations/call-declaration.ts | 77 +++++ .../records/annotations/custom-component.ts | 81 +++++ .../records/annotations/function.ts | 62 ++++ .../records/annotations/index.ts | 24 ++ .../annotations/normal-class-method.ts | 51 +++ .../annotations/normal-class-property.ts | 64 ++++ .../records/annotations/normal-class.ts | 56 +++ .../annotations/normal-interface-property.ts | 54 +++ .../records/annotations/struct-method.ts | 55 +++ .../records/annotations/struct-property.ts | 109 ++++++ .../collectors/ui-collectors/records/base.ts | 75 ++++ .../collectors/ui-collectors/records/cache.ts | 167 +++++++++ .../ui-collectors/records/call-declaration.ts | 140 ++++++++ .../ui-collectors/records/function-call.ts | 324 ++++++++++++++++++ .../ui-collectors/records/function.ts | 87 +++++ .../collectors/ui-collectors/records/index.ts | 31 ++ .../records/normal-class-method.ts | 91 +++++ .../records/normal-class-property.ts | 88 +++++ .../ui-collectors/records/normal-class.ts | 97 ++++++ .../records/normal-interface-property.ts | 89 +++++ .../ui-collectors/records/normal-interface.ts | 53 +++ .../ui-collectors/records/record-builder.ts | 45 +++ .../records/struct-interface-property.ts | 90 +++++ .../ui-collectors/records/struct-interface.ts | 66 ++++ .../ui-collectors/records/struct-method.ts | 95 +++++ .../ui-collectors/records/struct-property.ts | 83 +++++ .../ui-collectors/records/struct.ts | 93 +++++ .../collectors/ui-collectors/shared-types.ts | 27 ++ .../ui-collectors/struct-collector.ts | 157 +++++++++ .../struct-interface-collector.ts | 73 ++++ .../collectors/ui-collectors/ui-visitor.ts | 57 +++ .../collectors/ui-collectors/utils.ts | 180 ++++++++++ .../ui-collectors/validators/base.ts | 78 +++++ .../ui-collectors/validators/cache.ts | 33 ++ .../ui-collectors/validators/index.ts | 21 ++ .../normal-class-method-validator.ts | 33 ++ .../normal-class-property-validator.ts | 33 ++ .../validators/rules/check-builder-param.ts | 63 ++++ .../rules/check-component-link-init.ts | 51 +++ .../rules/check-component-v2-mix-use.ts | 135 ++++++++ .../rules/check-componentV2-state-usage.ts | 199 +++++++++++ .../rules/check-computed-decorator.ts | 246 +++++++++++++ .../check-consumer-provider-decorator.ts | 207 +++++++++++ .../rules/check-entry-localstorage.ts | 57 +++ .../rules/check-nested-relationship.ts | 55 +++ .../ui-collectors/validators/rules/index.ts | 22 ++ .../ui-collectors/validators/safe-types.ts | 30 ++ .../validators/struct-call-validator.ts | 38 ++ .../validators/struct-method-validator.ts | 34 ++ .../validators/struct-property-validator.ts | 42 +++ .../ui-collectors/validators/utils.ts | 38 ++ .../validators/validator-builder.ts | 27 ++ arkui-plugins/common/arkts-utils.ts | 20 +- arkui-plugins/common/declaration-collector.ts | 5 +- arkui-plugins/common/log-collector.ts | 74 +++- arkui-plugins/common/predefines.ts | 99 ++++-- arkui-plugins/common/safe-types.ts | 4 +- .../memo-plugins/function-transformer.ts | 5 +- arkui-plugins/memo-plugins/index.ts | 12 +- .../memo-plugins/memo-cache-factory.ts | 18 +- .../memo-plugins/parameter-transformer.ts | 8 +- .../component/declare-component.test.ts | 18 +- .../custom-dialog/base-custom-dialog.test.ts | 8 +- .../custom-dialog/controller-in-build.test.ts | 8 +- .../decorators/link/link-basic-type.test.ts | 22 +- .../decorators/link/link-complex-type.test.ts | 50 ++- .../link/link-to-link-prop-state.test.ts | 22 +- .../decorators/link/state-to-link.test.ts | 10 +- .../localstoragelink-complex-type.test.ts | 28 +- .../localstoragelink-primitive-type.test.ts | 12 +- .../localstorageprop-ref-complex-type.test.ts | 28 +- ...ocalstorageprop-ref-primitive-type.test.ts | 20 +- .../objectlink/objectlink-basic.test.ts | 4 +- .../objectlink/objectlink-observed.test.ts | 8 +- .../prop-ref/prop-ref-basic-type.test.ts | 20 +- .../prop-ref/prop-ref-complex-type.test.ts | 48 +-- .../prop-ref-without-initialization.test.ts | 42 +-- .../prop-ref/state-to-propref.test.ts | 8 +- .../decorators/prop/prop-basic-type.test.ts | 20 +- .../decorators/prop/prop-complex-type.test.ts | 48 +-- .../decorators/prop/state-to-prop.test.ts | 8 +- .../provide-annotation-usage.test.ts | 32 +- .../provide-basic-type.test.ts | 20 +- .../provide-complex-type.test.ts | 48 +-- .../reusable/reusable-basic.test.ts | 8 +- .../reusable/reusable-complex.test.ts | 8 +- .../decorators/state/state-basic-type.test.ts | 20 +- .../state/state-complex-type.test.ts | 48 +-- .../decorators/state/state-to-state.test.ts | 8 +- .../storagelink-appstorage.test.ts | 8 +- .../storagelink-complex-type.test.ts | 28 +- .../storagelink-primitive-type.test.ts | 12 +- .../storageprop-ref-complex-type.test.ts | 28 +- .../storageprop-ref-primitive-type.test.ts | 20 +- .../storageprop-appstorage.test.ts | 8 +- .../storageprop-complex-type.test.ts | 28 +- .../storageprop-primitive-type.test.ts | 12 +- .../decorators/watch/watch-basic.test.ts | 34 +- .../double-dollar-griditem.test.ts | 4 +- .../ut/ui-plugins/imports/kit-import.test.ts | 12 +- .../wrap-builder-with-lambda.test.ts | 8 +- .../test/utils/plugins/memo-no-recheck.ts | 10 +- .../builder-lambda-translators/factory.ts | 35 +- .../builder-lambda-translators/utils.ts | 16 +- .../ui-plugins/checked-transformer.ts | 25 +- .../ui-plugins/component-transformer.ts | 61 ++-- .../ui-plugins/entry-translators/factory.ts | 4 +- arkui-plugins/ui-plugins/index.ts | 4 +- .../ui-plugins/interop/builder-interop.ts | 3 +- .../ui-plugins/interop/initstatevar.ts | 3 +- arkui-plugins/ui-plugins/interop/interop.ts | 3 +- .../property-translators/builderParam.ts | 23 +- .../property-translators/consume.ts | 12 +- .../property-translators/factory.ts | 3 +- .../ui-plugins/property-translators/link.ts | 15 +- .../ui-plugins/property-translators/local.ts | 12 +- .../localStoragePropRef.ts | 12 +- .../property-translators/localstoragelink.ts | 12 +- .../property-translators/localstorageprop.ts | 12 +- .../property-translators/objectlink.ts | 13 +- .../property-translators/observedTrack.ts | 14 +- .../ui-plugins/property-translators/prop.ts | 15 +- .../property-translators/propRef.ts | 15 +- .../property-translators/provide.ts | 15 +- .../property-translators/regularProperty.ts | 13 +- .../ui-plugins/property-translators/state.ts | 15 +- .../property-translators/staticProperty.ts | 3 +- .../property-translators/storageProp.ts | 12 +- .../property-translators/storagePropRef.ts | 12 +- .../property-translators/storagelink.ts | 12 +- .../ui-plugins/property-translators/utils.ts | 30 +- .../ui-plugins/struct-translators/factory.ts | 10 +- .../struct-translators/struct-transformer.ts | 3 +- .../ui-plugins/struct-translators/utils.ts | 11 +- arkui-plugins/ui-plugins/ui-factory.ts | 5 +- arkui-plugins/ui-plugins/utils.ts | 43 +-- arkui-plugins/ui-syntax-plugins/index.ts | 81 ++++- .../ui-syntax-plugins/utils/index.ts | 2 +- koala-wrapper/native/src/bridges.cc | 154 ++++++++- koala-wrapper/native/src/common.cc | 69 +++- koala-wrapper/src/Es2pandaNativeModule.ts | 21 ++ koala-wrapper/src/arkts-api/class-by-peer.ts | 22 +- .../src/arkts-api/factory/nodeFactory.ts | 8 + koala-wrapper/src/arkts-api/index.ts | 1 + koala-wrapper/src/arkts-api/node-by-type.ts | 35 ++ .../node-utilities/ArrowFunctionExpression.ts | 6 +- .../node-utilities/CallExpression.ts | 6 +- .../arkts-api/node-utilities/ClassProperty.ts | 6 +- .../node-utilities/ETSFunctionType.ts | 6 +- .../node-utilities/ETSParameterExpression.ts | 6 +- .../arkts-api/node-utilities/ETSUnionType.ts | 6 +- .../arkts-api/node-utilities/Identifier.ts | 6 +- .../node-utilities/MethodDefinition.ts | 6 +- .../src/arkts-api/node-utilities/Property.ts | 6 +- .../node-utilities/ReturnStatement.ts | 6 +- .../node-utilities/ScriptFunction.ts | 6 +- .../arkts-api/node-utilities/SpreadElement.ts | 34 ++ .../node-utilities/TSTypeAliasDeclaration.ts | 6 +- .../node-utilities/VariableDeclarator.ts | 6 +- koala-wrapper/src/arkts-api/peers/AstNode.ts | 24 ++ .../src/arkts-api/static/globalUtils.ts | 2 +- koala-wrapper/src/arkts-api/types.ts | 4 +- .../src/arkts-api/utilities/nodeCache.ts | 64 +++- .../src/arkts-api/utilities/public.ts | 40 ++- koala-wrapper/src/arkts-api/visitor.ts | 5 + .../src/generated/peers/SpreadElement.ts | 38 +- koala-wrapper/src/reexport-for-generated.ts | 2 +- 175 files changed, 6443 insertions(+), 921 deletions(-) create mode 100644 arkui-plugins/collectors/ui-collectors/call-record-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/factory.ts create mode 100644 arkui-plugins/collectors/ui-collectors/global-class-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/normal-class-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/base.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/function.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/index.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/base.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/cache.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/call-declaration.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/function-call.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/function.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/index.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/normal-class.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/normal-interface.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/record-builder.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/struct-interface.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/struct-method.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/struct-property.ts create mode 100644 arkui-plugins/collectors/ui-collectors/records/struct.ts create mode 100644 arkui-plugins/collectors/ui-collectors/shared-types.ts create mode 100644 arkui-plugins/collectors/ui-collectors/struct-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts create mode 100644 arkui-plugins/collectors/ui-collectors/ui-visitor.ts create mode 100644 arkui-plugins/collectors/ui-collectors/utils.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/base.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/cache.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/index.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/rules/index.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/safe-types.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/struct-call-validator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/utils.ts create mode 100644 arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts create mode 100644 koala-wrapper/src/arkts-api/node-by-type.ts create mode 100644 koala-wrapper/src/arkts-api/node-utilities/SpreadElement.ts diff --git a/arkui-plugins/collectors/memo-collectors/function-collector.ts b/arkui-plugins/collectors/memo-collectors/function-collector.ts index a2751741f..ab200baef 100644 --- a/arkui-plugins/collectors/memo-collectors/function-collector.ts +++ b/arkui-plugins/collectors/memo-collectors/function-collector.ts @@ -15,6 +15,7 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; +import { NodeCacheNames } from '../../common/predefines'; import { checkIsMemoFromMemoableInfo, collectMemoableInfoInFunctionReturnType, @@ -56,14 +57,14 @@ export class MemoFunctionCollector extends AbstractVisitor { private collectMemoAstNode(node: arkts.AstNode, info: MemoableInfo): void { if (checkIsMemoFromMemoableInfo(info, false)) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } private collectCallWithDeclaredPeerInParamMap(node: arkts.CallExpression, peer: arkts.AstNode['peer']): void { const memoableInfo = this.paramMemoableInfoMap!.get(peer)!; if (checkIsMemoFromMemoableInfo(memoableInfo, true)) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } @@ -72,10 +73,11 @@ export class MemoFunctionCollector extends AbstractVisitor { declarator: arkts.VariableDeclarator ): void { const shouldCollect = - arkts.NodeCache.getInstance().has(declarator) || - (!!declarator.initializer && arkts.NodeCache.getInstance().has(declarator.initializer)); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(declarator) || + (!!declarator.initializer && + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(declarator.initializer)); if (shouldCollect) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } @@ -121,7 +123,7 @@ export class MemoFunctionCollector extends AbstractVisitor { } private visitCallExpression(node: arkts.CallExpression): arkts.AstNode { - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { this.disableCollectReturnBeforeCallback(() => { this.visitEachChild(node); }); @@ -135,8 +137,8 @@ export class MemoFunctionCollector extends AbstractVisitor { }); return node; } - if (arkts.NodeCache.getInstance().has(decl)) { - arkts.NodeCache.getInstance().collect(node); + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } if (this.paramMemoableInfoMap?.has(decl.peer)) { this.collectCallWithDeclaredPeerInParamMap(node, decl.peer); @@ -157,9 +159,9 @@ export class MemoFunctionCollector extends AbstractVisitor { return node; } if (this.paramMemoableInfoMap?.has(decl.peer)) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } else if (arkts.isEtsParameterExpression(decl) && this.paramMemoableInfoMap?.has(decl.identifier.peer)) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } return node; } @@ -168,7 +170,7 @@ export class MemoFunctionCollector extends AbstractVisitor { if (!!this.returnMemoableInfo && !!node.argument && arkts.isArrowFunctionExpression(node.argument)) { this.collectMemoAstNode(node.argument, this.returnMemoableInfo); } - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); this.visitEachChild(node); return node; } @@ -215,8 +217,8 @@ export class MemoFunctionCollector extends AbstractVisitor { } if ( arkts.isArrowFunctionExpression(node) && - !arkts.NodeCache.getInstance().has(node) && - !arkts.NodeCache.getInstance().has(node.scriptFunction) + !arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) && + !arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node.scriptFunction) ) { this.shouldCollectReturn = false; } diff --git a/arkui-plugins/collectors/memo-collectors/utils.ts b/arkui-plugins/collectors/memo-collectors/utils.ts index 1fe12a46d..8c04fdbd6 100644 --- a/arkui-plugins/collectors/memo-collectors/utils.ts +++ b/arkui-plugins/collectors/memo-collectors/utils.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { annotation, forEachArgWithParam, isDecoratorAnnotation } from '../../common/arkts-utils'; import { ImportCollector } from '../../common/import-collector'; -import { DecoratorNames, GenSymPrefix, MEMO_IMPORT_SOURCE_NAME } from '../../common/predefines'; +import { DecoratorNames, BuiltInNames, MEMO_IMPORT_SOURCE_NAME, NodeCacheNames } from '../../common/predefines'; import { MemoFunctionCollector } from './function-collector'; export enum MemoNames { @@ -77,11 +77,11 @@ export function addMemoAnnotation(node: T, memoName: Memo collectMemoAnnotationImport(memoName); if (arkts.isEtsParameterExpression(node)) { node.annotations = newAnnotations; - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); return node; } const newNode = node.setAnnotations(newAnnotations) as T; - arkts.NodeCache.getInstance().collect(newNode); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); return newNode; } @@ -120,7 +120,7 @@ export function collectMemoAnnotationSource(memoName: MemoNames = MemoNames.MEMO export function collectMemoableInfoInUnionType(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isETSUnionType(node)) { @@ -140,7 +140,7 @@ export function collectMemoableInfoInUnionType(node: arkts.AstNode, info?: Memoa export function collectMemoableInfoInTypeReference(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isETSTypeReference(node) || !node.part || !arkts.isETSTypeReferencePart(node.part)) { @@ -159,7 +159,7 @@ export function collectMemoableInfoInTypeReference(node: arkts.AstNode, info?: M export function collectMemoableInfoInFunctionType(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isETSFunctionType(node)) { @@ -172,7 +172,7 @@ export function collectMemoableInfoInFunctionType(node: arkts.AstNode, info?: Me export function collectMemoableInfoInTypeAlias(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isTSTypeAliasDeclaration(node)) { @@ -193,7 +193,7 @@ export function collectMemoableInfoInTypeAlias(node: arkts.AstNode, info?: Memoa export function collectMemoableInfoInParameter(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isEtsParameterExpression(node)) { @@ -220,7 +220,7 @@ export function collectMemoableInfoInParameter(node: arkts.AstNode, info?: Memoa export function collectMemoableInfoInVariableDeclarator(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isVariableDeclarator(node)) { @@ -264,7 +264,7 @@ export function collectMemoableInfoInVariableDeclarator(node: arkts.AstNode, inf export function collectMemoableInfoInProperty(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { const property = node as arkts.Property; const hasProperType = !!property.value && arkts.isArrowFunctionExpression(property.value); return { ...currInfo, hasMemo: true, hasProperType }; @@ -302,7 +302,7 @@ export function collectMemoableInfoInProperty(node: arkts.AstNode, info?: Memoab export function collectMemoableInfoInClassProperty(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isClassProperty(node)) { @@ -326,7 +326,7 @@ export function collectMemoableInfoInClassProperty(node: arkts.AstNode, info?: M export function collectMemoableInfoInArrowFunction(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isArrowFunctionExpression(node)) { @@ -358,7 +358,7 @@ export function collectMemoableInfoInArrowFunction(node: arkts.AstNode, info?: M export function collectMemoableInfoInScriptFunction(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isScriptFunction(node)) { @@ -399,13 +399,13 @@ export function collectMemoableInfoInType(node: arkts.AstNode, info?: MemoableIn export function collectMemoableInfoInFunctionReturnType(node: arkts.ScriptFunction): MemoableInfo { if (!!node.returnTypeAnnotation) { let memoableInfo: MemoableInfo; - if (arkts.NodeCache.getInstance().has(node.returnTypeAnnotation)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node.returnTypeAnnotation)) { memoableInfo = { hasMemo: true, hasProperType: true }; } else { memoableInfo = collectMemoableInfoInType(node.returnTypeAnnotation); } if ((memoableInfo.hasMemo || memoableInfo.hasBuilder) && memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(node.returnTypeAnnotation); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node.returnTypeAnnotation); } return memoableInfo; } @@ -416,7 +416,7 @@ export function collectGensymDeclarator(declarator: arkts.VariableDeclarator, in if (!info.hasMemo && !info.hasBuilder) { return; } - arkts.NodeCache.getInstance().collect(declarator); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(declarator); const initializer = declarator.initializer; if (!initializer || !arkts.isConditionalExpression(initializer)) { return; @@ -475,14 +475,18 @@ function collectMemoableInfoInFunctionParam( const peers: arkts.AstNode['peer'][] = []; let memoableInfo: MemoableInfo; const _param = param as arkts.ETSParameterExpression; - if (arkts.NodeCache.getInstance().has(_param)) { - const metadata = arkts.NodeCache.getInstance().get(_param)!.metadata ?? {}; + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(_param)) { + const metadata = arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(_param)!.metadata ?? {}; const { hasMemoSkip } = metadata; memoableInfo = { hasMemo: true, hasMemoSkip, hasProperType: true }; } else { memoableInfo = collectMemoableInfoInParameter(_param); } - if (_param.identifier.name.startsWith(GenSymPrefix.INTRINSIC) && !!node.body && arkts.isBlockStatement(node.body)) { + if ( + _param.identifier.name.startsWith(BuiltInNames.GENSYM_INTRINSIC_PREFIX) && + !!node.body && + arkts.isBlockStatement(node.body) + ) { const declaration = node.body.statements.at(gensymCount); if (!!declaration && arkts.isVariableDeclaration(declaration) && declaration.declarators.length > 0) { const declarator = declaration.declarators[0]; @@ -494,7 +498,9 @@ function collectMemoableInfoInFunctionParam( } } if (checkIsMemoFromMemoableInfo(memoableInfo)) { - arkts.NodeCache.getInstance().collect(_param, { hasMemoSkip: memoableInfo.hasMemoSkip }); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(_param, { hasMemoSkip: memoableInfo.hasMemoSkip }); } if (!memoableInfo.hasMemoSkip && shouldCollectParameter) { peers.push(_param.identifier.peer); @@ -516,7 +522,7 @@ export function findCanAddMemoFromTypeAnnotation( } const memoableInfo = collectMemoableInfoInType(typeAnnotation); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(typeAnnotation); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(typeAnnotation); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -530,7 +536,7 @@ export function findCanAddMemoFromTypeAnnotation( export function findCanAddMemoFromProperty(property: arkts.AstNode): property is arkts.Property { const memoableInfo = collectMemoableInfoInProperty(property); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(property); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(property); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -544,7 +550,7 @@ export function findCanAddMemoFromProperty(property: arkts.AstNode): property is export function findCanAddMemoFromClassProperty(property: arkts.AstNode): property is arkts.ClassProperty { const memoableInfo = collectMemoableInfoInClassProperty(property); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(property); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(property); } return ( (!!memoableInfo.hasBuilder || !!memoableInfo.hasBuilderParam) && @@ -565,7 +571,9 @@ export function findCanAddMemoFromParameter(param: arkts.AstNode | undefined): p } const memoableInfo = collectMemoableInfoInParameter(param); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(param, { hasMemoSkip: memoableInfo.hasMemoSkip }); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(param, { hasMemoSkip: memoableInfo.hasMemoSkip }); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -589,11 +597,15 @@ export function findCanAddMemoFromArrowFunction(node: arkts.AstNode): node is ar ); const isMemoReturnType = checkIsMemoFromMemoableInfo(returnMemoableInfo); if (isMemoReturnType) { - arkts.NodeCache.getInstance().collect(node.scriptFunction.returnTypeAnnotation!); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node.scriptFunction.returnTypeAnnotation!); } const isMemo = checkIsMemoFromMemoableInfo(memoableInfo); - if (isMemo && !arkts.NodeCache.getInstance().has(node)) { - arkts.NodeCache.getInstance().collect(node, { hasMemoEntry, hasMemoIntrinsic }); + if (isMemo && !arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasMemoEntry, hasMemoIntrinsic }); if (!!node.scriptFunction.body && arkts.isBlockStatement(node.scriptFunction.body)) { const disableCollectReturn = hasMemoEntry || hasMemoIntrinsic; collectMemoScriptFunctionBody( @@ -617,7 +629,7 @@ export function findCanAddMemoFromArrowFunction(node: arkts.AstNode): node is ar export function findCanAddMemoFromTypeAlias(node: arkts.AstNode): node is arkts.TSTypeAliasDeclaration { const memoableInfo = collectMemoableInfoInTypeAlias(node); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -642,15 +654,19 @@ export function findCanAddMemoFromMethod(node: arkts.AstNode): node is arkts.Met const isMemo = checkIsMemoFromMemoableInfo(memoableInfo); const isMemoReturnType = checkIsMemoFromMemoableInfo(returnMemoableInfo); if (isMemoReturnType) { - arkts.NodeCache.getInstance().collect(node.scriptFunction.returnTypeAnnotation!); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node.scriptFunction.returnTypeAnnotation!); } - if (isMemo && !arkts.NodeCache.getInstance().has(node)) { + if (isMemo && !arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { const metadata = collectMetadataInMethod(node); - arkts.NodeCache.getInstance().collect(node, { - ...metadata, - hasMemoEntry, - hasMemoIntrinsic, - }); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { + ...metadata, + hasMemoEntry, + hasMemoIntrinsic, + }); if (!!node.scriptFunction.body && arkts.isBlockStatement(node.scriptFunction.body)) { const disableCollectReturn = hasMemoEntry || hasMemoIntrinsic; collectMemoScriptFunctionBody( @@ -672,7 +688,7 @@ export function findCanAddMemoFromMethod(node: arkts.AstNode): node is arkts.Met * @param node `arkts.CallExpression` node. */ export function collectMemoFromCallExpression(node: arkts.CallExpression): void { - if (arkts.NodeCache.getInstance().has(node)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return; } const expr = findIdentifierFromCallee(node.expression); @@ -681,8 +697,8 @@ export function collectMemoFromCallExpression(node: arkts.CallExpression): void return; } let isCollected: boolean = false; - if (arkts.NodeCache.getInstance().has(decl)) { - arkts.NodeCache.getInstance().collect(node); + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); isCollected = true; } if (arkts.isMethodDefinition(decl)) { @@ -691,18 +707,18 @@ export function collectMemoFromCallExpression(node: arkts.CallExpression): void isCollected = collectCallWithDeclaredClassProperty(node, decl); } if (isCollected && arkts.isTSAsExpression(node.expression) && node.expression.typeAnnotation) { - arkts.NodeCache.getInstance().collect(node.expression.typeAnnotation); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node.expression.typeAnnotation); } } export function collectCallWithDeclaredClassProperty(node: arkts.CallExpression, decl: arkts.ClassProperty): boolean { - if (arkts.NodeCache.getInstance().has(decl)) { - arkts.NodeCache.getInstance().collect(node); + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); return true; } const memoableInfo = collectMemoableInfoInClassProperty(decl); if (checkIsMemoFromMemoableInfo(memoableInfo, false) || memoableInfo.hasBuilder || memoableInfo.hasBuilderParam) { - arkts.NodeCache.getInstance().collect(node); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); return true; } return false; @@ -716,15 +732,20 @@ export function collectCallWithDeclaredMethod(node: arkts.CallExpression, decl: const isTrailingCall = node.isTrailingCall; const options = { hasRestParameter, isTrailingCall }; forEachArgWithParam(args, params, collectCallArgsWithMethodParams, options); - if (arkts.NodeCache.getInstance().has(decl)) { - const { hasMemoEntry, hasMemoIntrinsic } = arkts.NodeCache.getInstance().get(decl)!.metadata ?? {}; - arkts.NodeCache.getInstance().collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + const { hasMemoEntry, hasMemoIntrinsic } = + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(decl)!.metadata ?? {}; + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); return true; } else { const memoableInfo = collectMemoableInfoInScriptFunction(decl.scriptFunction); if (checkIsMemoFromMemoableInfo(memoableInfo, true)) { const { hasMemoEntry, hasMemoIntrinsic } = memoableInfo; - arkts.NodeCache.getInstance().collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); return true; } } @@ -736,13 +757,13 @@ export function collectCallArgsWithMethodParams(arg: arkts.Expression | undefine return; } let info: MemoableInfo; - if (arkts.NodeCache.getInstance().has(param)) { + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(param)) { info = { hasMemo: true, hasProperType: true }; } else { info = collectMemoableInfoInParameter(param); } if (checkIsMemoFromMemoableInfo(info) && arkts.isArrowFunctionExpression(arg)) { - arkts.NodeCache.getInstance().collect(arg); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(arg); const returnMemoableInfo = collectMemoableInfoInFunctionReturnType(arg.scriptFunction); const [paramMemoableInfoMap, gensymCount] = collectMemoableInfoMapInFunctionParams(arg.scriptFunction); if (!!arg.scriptFunction.body && arkts.isBlockStatement(arg.scriptFunction.body)) { diff --git a/arkui-plugins/collectors/ui-collectors/call-record-collector.ts b/arkui-plugins/collectors/ui-collectors/call-record-collector.ts new file mode 100644 index 000000000..021cc24cb --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/call-record-collector.ts @@ -0,0 +1,106 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { CallInfo, CallRecord } from './records'; +import { UICollectMetadata } from './shared-types'; +import { findRootCallee, findRootCallObject } from './utils'; +import { StructCallValidator, ValidatorBuilder } from './validators'; + +export interface CallRecordInfo { + call: arkts.CallExpression; + callInfo: CallInfo; +} + +export class CallRecordCollector { + private static instance: CallRecordCollector; + private _metadata: UICollectMetadata; + private _rootCallInfo?: CallRecordInfo; + private _prevCallInfo?: CallRecordInfo; + private _chainingCallNames?: string[]; + private _shouldCollectPreviousCall: boolean = false; + + private constructor(metadata: UICollectMetadata) { + this._metadata = metadata; + } + + static getInstance(metadata: UICollectMetadata): CallRecordCollector { + if (!this.instance) { + this.instance = new CallRecordCollector(metadata); + } + return this.instance; + } + + private get prevCallInfo(): CallRecordInfo | undefined { + return this._prevCallInfo; + } + + private set prevCallInfo(prevCallInfo: CallRecordInfo | undefined) { + if (this._shouldCollectPreviousCall && prevCallInfo?.callInfo.ptr !== this._prevCallInfo?.callInfo.ptr) { + this.finishLastCollectInPreviousCall(); + this._shouldCollectPreviousCall = false; + } + this._prevCallInfo = prevCallInfo; + if (this._prevCallInfo !== undefined) { + this._shouldCollectPreviousCall = true; + } + } + + private finishLastCollectInPreviousCall(): void { + if (!this._prevCallInfo) { + return; + } + // TODO: cache the call with full chaining + const { call, callInfo } = this._prevCallInfo; + // console.log('[CALL] node: ', call.dumpSrc()); + // console.log('[CALL] node info: ', callInfo); + ValidatorBuilder.build(StructCallValidator).checkIsViolated(call, callInfo); + } + + reset() { + this.prevCallInfo = undefined; + this._rootCallInfo = undefined; + this._chainingCallNames = undefined; + this._shouldCollectPreviousCall = false; + } + + collect(call: arkts.CallExpression): void { + const callRecord = new CallRecord(this._metadata); + + const rootCallObject = findRootCallObject(call.expression); + const rootCallee = findRootCallee(call.expression); + callRecord.withRootCallObject(rootCallObject).withRootCallee(rootCallee); + const isWithInChain = !!this._rootCallInfo && call.expression.findNodeInInnerChild(this._rootCallInfo.call); + if (isWithInChain) { + if (!!rootCallee?.name) { + this._chainingCallNames?.push(rootCallee.name); + } + callRecord.withRootCallInfo(this._rootCallInfo!.callInfo); + } else { + this._chainingCallNames = !!rootCallee?.name ? [rootCallee.name] : undefined; + } + if (!!this._chainingCallNames) { + callRecord.withChainingCallNames(this._chainingCallNames); + } + + callRecord.collect(call); + const callInfo = callRecord.toRecord()!; + if (!isWithInChain) { + this._rootCallInfo = { call, callInfo }; + this.finishLastCollectInPreviousCall(); + } + this.prevCallInfo = { call, callInfo }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/factory.ts b/arkui-plugins/collectors/ui-collectors/factory.ts new file mode 100644 index 000000000..87a652c6f --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/factory.ts @@ -0,0 +1,163 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { + checkIsCustomComponentDeclaredClassFromInfo, + checkIsCustomComponentFromInfo, + checkIsObservedClassFromInfo, + checkIsETSGlobalClassFromInfo, + checkIsCommonMethodInterfaceFromInfo, +} from './utils'; +import { + CustomComponentInterfaceRecord, + CustomComponentRecord, + NormalClassRecord, + NormalInterfaceRecord, +} from './records'; +import { StructCollector } from './struct-collector'; +import { GlobalClassCollector } from './global-class-collector'; +import { NormalClassCollector } from './normal-class-collector'; +import { StructInterfaceCollector } from './struct-interface-collector'; +import { NormalInterfaceCollector } from './normal-interface-collector'; +import { CallRecordCollector } from './call-record-collector'; +import { UICollectMetadata } from './shared-types'; +import { ARKUI_COMPONENT_COMMON_SOURCE_NAME, NodeCacheNames } from '../../common/predefines'; +import { LogCollector } from '../../common/log-collector'; + +export function findAndCollectUINodeInPreOrder(node: arkts.AstNode, metadata?: UICollectMetadata): void { + const type = arkts.nodeType(node); + if (preOrderCollectByType.has(type)) { + preOrderCollectByType.get(type)!(node, metadata); + } +} + +export function findAndCollectUINodeInPostOrder(node: arkts.AstNode, metadata?: UICollectMetadata): void { + const type = arkts.nodeType(node); + if (postOrderCollectByType.has(type)) { + postOrderCollectByType.get(type)!(node, metadata); + } +} + +export class CollectFactory { + static findAndCollectClass(node: arkts.ClassDeclaration, metadata: UICollectMetadata): arkts.AstNode { + const structRecord = new CustomComponentRecord(metadata); + structRecord.collect(node); + + let classInfo = structRecord.toRecord(); + if (!!classInfo && checkIsCustomComponentFromInfo(classInfo)) { + // TODO: collect CustomComponent Class + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, structRecord.toJSON()); + const structCollector = new StructCollector({ ...metadata, structRecord }); + structCollector.visitor(node); + structCollector.reset(); + // console.log("[STRUCT] node: ", node.dumpSrc()); + return node; + } + if (!!classInfo && checkIsCustomComponentDeclaredClassFromInfo(classInfo)) { + // TODO: collect CustomComponent Declaration Class + const structCollector = new StructCollector({ ...metadata, structRecord }); + structCollector.disableCollectProperty().visitor(node); + structCollector.reset(); + // console.log("[CUSTOM COMPONENT DECL] node: ", node.dumpSrc()); + return node; + } + + const classRecord = new NormalClassRecord(metadata); + classRecord.collect(node); + + classInfo = classRecord.toRecord(); + // console.log("[CLASS] node: ", node.dumpSrc()); + // console.log("[CLASS] classInfo: ", classInfo?.annotationInfo); + if (!!classInfo && checkIsETSGlobalClassFromInfo(classInfo)) { + const globalClassCollector = new GlobalClassCollector(metadata); + globalClassCollector.visitor(node); + globalClassCollector.reset(); + // console.log("[ETSGLOBAL CLASS] node: ", node.dumpSrc()); + return node; + } + if (!!classInfo) { + if (checkIsObservedClassFromInfo(classInfo)) { + // TODO: collect @Observed Normal Class + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, classRecord.toJSON()); + } + const normalClassCollector = new NormalClassCollector({ ...metadata, classRecord }); + normalClassCollector.visitor(node); + normalClassCollector.reset(); + // console.log("[NORMAL CLASS] node: ", node.dumpSrc()); + return node; + } + return node; + } + + static findAndCollectInterface(node: arkts.TSInterfaceDeclaration, metadata: UICollectMetadata): arkts.AstNode { + const interfaceRecord = new CustomComponentInterfaceRecord(metadata); + interfaceRecord.collect(node); + + let interfaceInfo = interfaceRecord.toRecord(); + if (!!interfaceInfo && checkIsCustomComponentFromInfo(interfaceInfo)) { + // TODO: collect __Options_ CustomComponent Interface + const interfaceCollector = new StructInterfaceCollector({ ...metadata, interfaceRecord }); + interfaceCollector.visitor(node); + interfaceCollector.reset(); + // console.log("[STRUCT INTERFACE] node: ", node.dumpSrc()); + return node; + } + + const normalInterfaceRecord = new NormalInterfaceRecord(metadata); + normalInterfaceRecord.collect(node); + + interfaceInfo = normalInterfaceRecord.toRecord(); + if ( + metadata.externalSourceName === ARKUI_COMPONENT_COMMON_SOURCE_NAME && + checkIsCommonMethodInterfaceFromInfo(interfaceInfo) + ) { + // TODO: collect CommonMethod Declared Interface + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(node, normalInterfaceRecord.toJSON()); + } + + const interfaceCollector = new NormalInterfaceCollector({ + ...metadata, + interfaceRecord: normalInterfaceRecord, + }); + interfaceCollector.visitor(node); + interfaceCollector.reset(); + // console.log("[INTERFACE METHOD] node: ", node.dumpSrc()); + + return node; + } + + static findAndCollectCall(node: arkts.CallExpression, metadata: UICollectMetadata): arkts.AstNode { + CallRecordCollector.getInstance(metadata).collect(node); + return node; + } + + static visitETSModule(node: arkts.EtsScript, metadata: UICollectMetadata): arkts.AstNode { + LogCollector.getInstance().emitLogInfo(); + return node; + } +} + +const preOrderCollectByType = new Map arkts.AstNode>([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, CollectFactory.findAndCollectClass], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION, CollectFactory.findAndCollectInterface], +]); + +const postOrderCollectByType = new Map arkts.AstNode>([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, CollectFactory.findAndCollectCall], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_MODULE, CollectFactory.visitETSModule], +]); diff --git a/arkui-plugins/collectors/ui-collectors/global-class-collector.ts b/arkui-plugins/collectors/ui-collectors/global-class-collector.ts new file mode 100644 index 000000000..4b04d3c94 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/global-class-collector.ts @@ -0,0 +1,58 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { NodeCacheNames } from '../../common/predefines'; +import { FunctionRecord } from './records/function'; + +export interface GlobalClassCollectorOptions extends VisitorOptions { + shouldIgnoreDecl?: boolean; +} + +export class GlobalClassCollector extends AbstractVisitor { + public shouldIgnoreDecl: boolean; + + constructor(options: GlobalClassCollectorOptions) { + super(options); + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + } + + private collectMethod(node: arkts.MethodDefinition): void { + const methodRecord = new FunctionRecord({ + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + methodRecord.collect(node); + + const methodInfo = methodRecord.toRecord(); + if (!methodInfo || methodInfo.isGlobalInit || methodInfo.isGlobalMain) { + return; + } + if (!!methodInfo.annotationInfo && Object.keys(methodInfo.annotationInfo).length > 0) { + // TODO: collect method info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + // console.log("[ETSGLOBAL CLASS METHOD] node: ", node.dumpSrc()); + } + } + + visitor(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + node.definition?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/normal-class-collector.ts b/arkui-plugins/collectors/ui-collectors/normal-class-collector.ts new file mode 100644 index 000000000..934b71199 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/normal-class-collector.ts @@ -0,0 +1,143 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { + NormalClassMethodRecord, + NormalClassPropertyInfo, + NormalClassPropertyRecord, + NormalClassRecord, +} from './records'; +import { BuiltInNames, NodeCacheNames } from '../../common/predefines'; +import { formatBuiltInImplementedPropertyName } from './utils'; +import { NormalClassMethodValidator, NormalClassPropertyValidator, ValidatorBuilder } from './validators'; + +export interface NormalClassCollectorOptions extends VisitorOptions { + classRecord: NormalClassRecord; + shouldIgnoreDecl?: boolean; +} + +interface MethodRecordCollection { + node: arkts.MethodDefinition; + record: NormalClassMethodRecord; +} + +export class NormalClassCollector extends AbstractVisitor { + private _classRecord: NormalClassRecord; + public shouldIgnoreDecl: boolean; + + private _getters: MethodRecordCollection[]; + private _setters: MethodRecordCollection[]; + private _implementedPropertyNames: string[]; + + constructor(options: NormalClassCollectorOptions) { + super(options); + this._classRecord = options.classRecord; + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + this._getters = []; + this._setters = []; + this._implementedPropertyNames = []; + } + + private canCollectPropertyFromInfo(info: NormalClassPropertyInfo): boolean { + if (info.classInfo?.annotationInfo?.hasObserved) { + return true; + } + if (!!info.annotationInfo && Object.keys(info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private collectProperty(node: arkts.ClassProperty): void { + const propertyRecord = new NormalClassPropertyRecord({ + classRecord: this._classRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + propertyRecord.collect(node); + + const propertyInfo = propertyRecord.toRecord(); + if (!propertyInfo) { + return; + } + if (this.canCollectPropertyFromInfo(propertyInfo)) { + if (propertyInfo.name?.startsWith(BuiltInNames.IMPLEMENT_PROPETY_PREFIX)) { + this._implementedPropertyNames.push(formatBuiltInImplementedPropertyName(propertyInfo.name)); + } + // TODO: collect property info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, propertyRecord.toJSON()); + } + // console.log('[NORMAL CLASS PROPERTY] node: ', node.dumpSrc()); + ValidatorBuilder.build(NormalClassPropertyValidator).checkIsViolated(node, propertyInfo); + } + + private rememberMethod(node: arkts.MethodDefinition, record: NormalClassMethodRecord): void { + if (node.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + this._getters.push({ node, record }); + } + if (node.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + this._setters.push({ node, record }); + } + } + + private collectMethod(node: arkts.MethodDefinition): void { + const methodRecord = new NormalClassMethodRecord({ + classRecord: this._classRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + methodRecord.collect(node); + + const methodInfo = methodRecord.toRecord(); + if (!methodInfo) { + return; + } + + if (this._implementedPropertyNames.includes(node.name.name)) { + this.rememberMethod(node, methodRecord); + } + // console.log('[NORMAL CLASS METHOD] node: ', node.dumpSrc()); + // console.log('[NORMAL CLASS METHOD] methodInfo: ', methodInfo); + ValidatorBuilder.build(NormalClassMethodValidator).checkIsViolated(node, methodInfo); + } + + private cacheMethod(collection: MethodRecordCollection) { + arkts.NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(collection.node, collection.record.toJSON()); + } + + reset(): void { + super.reset(); + this._getters = []; + this._setters = []; + this._implementedPropertyNames = []; + } + + visitor(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + node.definition?.body.forEach((st) => { + if (arkts.isClassProperty(st)) { + this.collectProperty(st); + } else if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + if (this._implementedPropertyNames.length > 0) { + this._getters.forEach((collection) => this.cacheMethod(collection)); + this._setters.forEach((collection) => this.cacheMethod(collection)); + } + return node; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts b/arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts new file mode 100644 index 000000000..ee0f00e3c --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts @@ -0,0 +1,73 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { + NormalInterfacePropertyInfo, + NormalInterfacePropertyRecord, + NormalInterfaceRecord, +} from './records'; +import { NodeCacheNames } from '../../common/predefines'; + +export interface NormalInterfaceCollectorOptions extends VisitorOptions { + interfaceRecord: NormalInterfaceRecord; + shouldIgnoreDecl?: boolean; +} + +export class NormalInterfaceCollector extends AbstractVisitor { + private _interfaceRecord: NormalInterfaceRecord; + public shouldIgnoreDecl: boolean; + + constructor(options: NormalInterfaceCollectorOptions) { + super(options); + this._interfaceRecord = options.interfaceRecord; + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + } + + private canCollectMethodFromInfo(info: NormalInterfacePropertyInfo): boolean { + if (!!info.annotationInfo && Object.keys(info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private collectMethod(node: arkts.MethodDefinition): void { + const methodRecord = new NormalInterfacePropertyRecord({ + interfaceRecord: this._interfaceRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + methodRecord.collect(node); + + const methodInfo = methodRecord.toRecord(); + if (!methodInfo) { + return; + } + if (this.canCollectMethodFromInfo(methodInfo)) { + // TODO: collect method info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + // console.log("[INTERFACE METHOD] node: ", node.dumpSrc()); + } + } + + visitor(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + node.body?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts new file mode 100644 index 000000000..8f8303a2c --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts @@ -0,0 +1,132 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { getAnnotationName } from '../../utils'; +import { BaseRecord, RecordOptions } from '../base'; + +export type Annotations = { + [K in string]?: arkts.AnnotationUsage; +}; + +export type AnnotationInfo = { + [K in string as `has${K}`]?: boolean; +}; + +export type AnnotationRecord = { + annotations?: U; + annotationInfo?: V; + ignoredAnnotations?: Annotations; + ignoredAnnotationInfo?: AnnotationInfo; +}; + +function firstToLower(str: string): string { + return str.charAt(0).toLowerCase() + str.slice(1); +} + +export abstract class BaseAnnotationRecord< + U extends Annotations = Annotations, + V extends AnnotationInfo = AnnotationInfo +> extends BaseRecord> { + protected abstract annotationNames: string[]; + protected _annotations: U = {} as U; + protected _annotationInfo: V = {} as V; + + protected _ignoredAnnotations: Annotations = {}; + protected _ignoredAnnotationInfo: AnnotationInfo = {}; + + constructor(options: RecordOptions) { + super(options); + } + + public get annotations(): U | undefined { + if (Object.keys(this._annotations).length === 0) { + return undefined; + } + return this._annotations; + } + + public get annotationInfo(): V | undefined { + if (Object.keys(this._annotationInfo).length === 0) { + return undefined; + } + return this._annotationInfo; + } + + public get ignoredAnnotations(): Annotations | undefined { + if (Object.keys(this._ignoredAnnotations).length === 0) { + return undefined; + } + return this._ignoredAnnotations; + } + + public get ignoredAnnotationInfo(): AnnotationInfo | undefined { + if (Object.keys(this._ignoredAnnotationInfo).length === 0) { + return undefined; + } + return this._ignoredAnnotationInfo; + } + + private updateAnnotationInfo(name: string | undefined): void { + const newInfo = this.updateAnnotationInfoByName(this._annotationInfo, name); + this._annotationInfo = newInfo; + } + + private updateAnnotations(anno: arkts.AnnotationUsage, name: string | undefined): void { + if (!!name && !!this._annotationInfo[`has${name}`] && !this._annotations[name]) { + this._annotations = { ...this._annotations, [name]: anno }; + } + } + + private updateIgnoreAnnotationInfo(name: string | undefined): void { + if (!!name && !this.annotationNames.includes(name)) { + this._ignoredAnnotationInfo[`has${name}`] = true; + } + } + + private updateIgnoreAnnotations(anno: arkts.AnnotationUsage, name: string | undefined): void { + if (!!name && !!this._ignoredAnnotationInfo[`has${name}`] && !this._ignoredAnnotations[name]) { + this._ignoredAnnotations = { ...this._ignoredAnnotations, [name]: anno }; + } + } + + collectFromNode(node: arkts.AnnotationUsage): void { + const name = getAnnotationName(node, this.shouldIgnoreDecl); + this.updateAnnotationInfo(name); + this.updateAnnotations(node, name); + this.updateIgnoreAnnotationInfo(name); + this.updateIgnoreAnnotations(node, name); + } + + refreshOnce(): void { + const currInfo: AnnotationRecord = { + ...this.info, + ...(this.annotations && { annotations: this.annotations }), + ...(this.annotationInfo && { annotationInfo: this.annotationInfo }), + ...(this.ignoredAnnotations && { ignoredAnnotations: this.ignoredAnnotations }), + ...(this.ignoredAnnotationInfo && { ignoredAnnotationInfo: this.ignoredAnnotationInfo }), + }; + this.info = currInfo; + } + + toJSON(): AnnotationRecord { + this.refresh(); + return { + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } + + abstract updateAnnotationInfoByName(info: V, name: string | undefined): V; +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts new file mode 100644 index 000000000..7c7dd162f --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts @@ -0,0 +1,77 @@ +/* + * 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 { FunctionAnnotationInfo, FunctionAnnotations } from './function'; +import { StructPropertyAnnotationInfo, StructPropertyAnnotations } from './struct-property'; +import { StructMethodAnnotationInfo, StructMethodAnnotations } from './struct-method'; +import { NormalClassPropertyAnnotationInfo, NormalClassPropertyAnnotations } from './normal-class-property'; +import { NormalClassMethodAnnotationInfo, NormalClassMethodAnnotations } from './normal-class-method'; +import { BaseAnnotationRecord } from './base'; +import { RecordOptions } from '../base'; +import { BuilderLambdaNames, DecoratorNames } from '../../../../common/predefines'; + +export type CallDeclAnnotationInfo = FunctionAnnotationInfo & + StructPropertyAnnotationInfo & + StructMethodAnnotationInfo & + NormalClassPropertyAnnotationInfo & + NormalClassMethodAnnotationInfo; + +export type CallDeclAnnotations = FunctionAnnotations & + StructPropertyAnnotations & + StructMethodAnnotations & + NormalClassPropertyAnnotations & + NormalClassMethodAnnotations; + +export class CallDeclAnnotationRecord extends BaseAnnotationRecord { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.annotationNames = [ + DecoratorNames.BUILDER, + DecoratorNames.ANIMATABLE_EXTEND, + BuilderLambdaNames.ANNOTATION_NAME, + DecoratorNames.STATE, + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP, + DecoratorNames.LINK, + DecoratorNames.PROP, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.OBJECT_LINK, + DecoratorNames.WATCH, + DecoratorNames.BUILDER_PARAM, + DecoratorNames.LOCAL_STORAGE_PROP, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.PROP_REF, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL, + DecoratorNames.PARAM, + DecoratorNames.EVENT, + DecoratorNames.REQUIRE, + DecoratorNames.COMPUTED, + DecoratorNames.JSONSTRINGIFYIGNORE, + DecoratorNames.JSONRENAME, + DecoratorNames.TRACK, + ]; + } + + updateAnnotationInfoByName(info: CallDeclAnnotationInfo, name: string | undefined): CallDeclAnnotationInfo { + if (!!name && this.annotationNames.includes(name)) { + info[`has${name}`] = true; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts new file mode 100644 index 000000000..d727da321 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { StructDecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface StructAnnotationInfo extends AnnotationInfo { + hasComponent?: boolean; + hasComponentV2?: boolean; + hasEntry?: boolean; + hasReusable?: boolean; + hasReusableV2?: boolean; + hasCustomLayout?: boolean; + hasCustomDialog?: boolean; +} + +export interface CustomComponentAnnotations extends Annotations { + [StructDecoratorNames.COMPONENT]?: arkts.AnnotationUsage; + [StructDecoratorNames.COMPONENT_V2]?: arkts.AnnotationUsage; + [StructDecoratorNames.ENTRY]?: arkts.AnnotationUsage; + [StructDecoratorNames.RESUABLE]?: arkts.AnnotationUsage; + [StructDecoratorNames.RESUABLE_V2]?: arkts.AnnotationUsage; + [StructDecoratorNames.CUSTOM_LAYOUT]?: arkts.AnnotationUsage; + [StructDecoratorNames.CUSTOMDIALOG]?: arkts.AnnotationUsage; +} + +export class CustomComponentAnnotationRecord extends BaseAnnotationRecord< + CustomComponentAnnotations, + StructAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = Object.values(StructDecoratorNames); + } + + updateAnnotationInfoByName(info: StructAnnotationInfo, name: string | undefined): StructAnnotationInfo { + switch (name) { + case StructDecoratorNames.COMPONENT: + info.hasComponent = true; + break; + case StructDecoratorNames.COMPONENT_V2: + info.hasComponentV2 = true; + break; + case StructDecoratorNames.ENTRY: + info.hasEntry = true; + break; + case StructDecoratorNames.RESUABLE: + info.hasReusable = true; + break; + case StructDecoratorNames.RESUABLE_V2: + info.hasReusableV2 = true; + break; + case StructDecoratorNames.CUSTOM_LAYOUT: + info.hasCustomLayout = true; + break; + case StructDecoratorNames.CUSTOMDIALOG: + info.hasCustomDialog = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts new file mode 100644 index 000000000..f0c96ad81 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts @@ -0,0 +1,62 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { BuilderLambdaNames, DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface FunctionAnnotationInfo extends AnnotationInfo { + hasBuilder?: boolean; + hasAnimatableExtend?: boolean; + hasComponentBuilder?: boolean; +} + +export interface FunctionAnnotations extends Annotations { + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; + [DecoratorNames.ANIMATABLE_EXTEND]?: arkts.AnnotationUsage; + [BuilderLambdaNames.ANNOTATION_NAME]?: arkts.AnnotationUsage; +} + +export class FunctionAnnotationRecord extends BaseAnnotationRecord { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [ + DecoratorNames.BUILDER, + DecoratorNames.ANIMATABLE_EXTEND, + BuilderLambdaNames.ANNOTATION_NAME, + ]; + } + + updateAnnotationInfoByName(info: FunctionAnnotationInfo, name: string | undefined): FunctionAnnotationInfo { + switch (name) { + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + case DecoratorNames.ANIMATABLE_EXTEND: + info.hasAnimatableExtend = true; + break; + case BuilderLambdaNames.ANNOTATION_NAME: + info.hasComponentBuilder = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts new file mode 100644 index 000000000..5600cd48e --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export * from './custom-component'; +export * from './normal-class'; +export * from './normal-class-property'; +export * from './normal-class-method'; +export * from './function'; +export * from './struct-property'; +export * from './struct-method'; +export * from './normal-interface-property'; +export * from './call-declaration'; \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts new file mode 100644 index 000000000..b26e9e307 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts @@ -0,0 +1,51 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface NormalClassMethodAnnotationInfo extends AnnotationInfo { + hasComputed?: boolean; +} + +export interface NormalClassMethodAnnotations extends Annotations { + [DecoratorNames.COMPUTED]?: arkts.AnnotationUsage; +} + +export class NormalClassMethodAnnotationRecord extends BaseAnnotationRecord< + NormalClassMethodAnnotations, + NormalClassMethodAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [DecoratorNames.COMPUTED]; + } + + updateAnnotationInfoByName(info: NormalClassMethodAnnotationInfo, name: string | undefined): NormalClassMethodAnnotationInfo { + switch (name) { + case DecoratorNames.COMPUTED: + info.hasComputed = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts new file mode 100644 index 000000000..67a00e3e9 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts @@ -0,0 +1,64 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface NormalClassPropertyAnnotationInfo extends AnnotationInfo { + hasJsonStringifyIgnore?: boolean; + hasJsonRename?: boolean; + hasTrack?: boolean; +} + +export interface NormalClassPropertyAnnotations extends Annotations { + [DecoratorNames.JSONSTRINGIFYIGNORE]?: arkts.AnnotationUsage; + [DecoratorNames.JSONRENAME]?: arkts.AnnotationUsage; + [DecoratorNames.TRACK]?: arkts.AnnotationUsage; +} + +export class NormalClassPropertyAnnotationRecord extends BaseAnnotationRecord< + NormalClassPropertyAnnotations, + NormalClassPropertyAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [DecoratorNames.JSONSTRINGIFYIGNORE, DecoratorNames.JSONRENAME, DecoratorNames.TRACK]; + } + + updateAnnotationInfoByName( + info: NormalClassPropertyAnnotationInfo, + name: string | undefined + ): NormalClassPropertyAnnotationInfo { + switch (name) { + case DecoratorNames.JSONSTRINGIFYIGNORE: + info.hasJsonStringifyIgnore = true; + break; + case DecoratorNames.JSONRENAME: + info.hasJsonRename = true; + break; + case DecoratorNames.TRACK: + info.hasTrack = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts new file mode 100644 index 000000000..9f2e1587f --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts @@ -0,0 +1,56 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface NormalClassAnnotationInfo extends AnnotationInfo { + hasObserved?: boolean; + hasObservedV2?: boolean; +} + +export interface NormalClassAnnotations extends Annotations { + [DecoratorNames.OBSERVED]?: arkts.AnnotationUsage; + [DecoratorNames.OBSERVED_V2]?: arkts.AnnotationUsage; +} + +export class NormalClassAnnotationRecord extends BaseAnnotationRecord< + NormalClassAnnotations, + NormalClassAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [DecoratorNames.OBSERVED, DecoratorNames.OBSERVED_V2]; + } + + updateAnnotationInfoByName(info: NormalClassAnnotationInfo, name: string | undefined): NormalClassAnnotationInfo { + switch (name) { + case DecoratorNames.OBSERVED: + info.hasObserved = true; + break; + case DecoratorNames.OBSERVED_V2: + info.hasObservedV2 = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts new file mode 100644 index 000000000..26848161d --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts @@ -0,0 +1,54 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface NormalInterfacePropertyAnnotationInfo extends AnnotationInfo { + hasBuilder?: boolean; +} + +export interface NormalInterfacePropertyAnnotations extends Annotations { + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; +} + +export class NormalInterfacePropertyAnnotationRecord extends BaseAnnotationRecord< + NormalInterfacePropertyAnnotations, + NormalInterfacePropertyAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [DecoratorNames.BUILDER]; + } + + updateAnnotationInfoByName( + info: NormalInterfacePropertyAnnotationInfo, + name: string | undefined + ): NormalInterfacePropertyAnnotationInfo { + switch (name) { + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts new file mode 100644 index 000000000..1a4b01330 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts @@ -0,0 +1,55 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface StructMethodAnnotationInfo extends AnnotationInfo { + hasBuilder?: boolean; + hasComputed?: boolean; +} + +export interface StructMethodAnnotations extends Annotations { + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; + [DecoratorNames.COMPUTED]?: arkts.AnnotationUsage; +} + +export class StructMethodAnnotationRecord extends BaseAnnotationRecord< + StructMethodAnnotations, + StructMethodAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.annotationNames = [DecoratorNames.BUILDER, DecoratorNames.COMPUTED]; + } + + updateAnnotationInfoByName(info: StructMethodAnnotationInfo, name: string | undefined): StructMethodAnnotationInfo { + switch (name) { + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + case DecoratorNames.COMPUTED: + info.hasComputed = true; + break; + default: + return info; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts b/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts new file mode 100644 index 000000000..d709d5d78 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts @@ -0,0 +1,109 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface StructPropertyAnnotationInfo extends AnnotationInfo { + hasState?: boolean; + hasStorageLink?: boolean; + hasStorageProp?: boolean; + hasLink?: boolean; + hasProp?: boolean; + hasProvide?: boolean; + hasConsume?: boolean; + hasObjectLink?: boolean; + hasWatch?: boolean; + hasBuilderParam?: boolean; + hasLocalStorageProp?: boolean; + hasLocalStorageLink?: boolean; + hasPropRef?: boolean; + hasStoragePropRef?: boolean; + hasLocal?: boolean; + hasParam?: boolean; + hasEvent?: boolean; + hasRequire?: boolean; + hasConsumer?: boolean; + hasProvider?: boolean; +} + +export interface StructPropertyAnnotations extends Annotations { + [DecoratorNames.STATE]?: arkts.AnnotationUsage; + [DecoratorNames.STORAGE_LINK]?: arkts.AnnotationUsage; + [DecoratorNames.STORAGE_PROP]?: arkts.AnnotationUsage; + [DecoratorNames.LINK]?: arkts.AnnotationUsage; + [DecoratorNames.PROP]?: arkts.AnnotationUsage; + [DecoratorNames.PROVIDE]?: arkts.AnnotationUsage; + [DecoratorNames.CONSUME]?: arkts.AnnotationUsage; + [DecoratorNames.OBJECT_LINK]?: arkts.AnnotationUsage; + [DecoratorNames.WATCH]?: arkts.AnnotationUsage; + [DecoratorNames.BUILDER_PARAM]?: arkts.AnnotationUsage; + [DecoratorNames.LOCAL_STORAGE_PROP]?: arkts.AnnotationUsage; + [DecoratorNames.LOCAL_STORAGE_LINK]?: arkts.AnnotationUsage; + [DecoratorNames.PROP_REF]?: arkts.AnnotationUsage; + [DecoratorNames.STORAGE_PROP_REF]?: arkts.AnnotationUsage; + [DecoratorNames.LOCAL]?: arkts.AnnotationUsage; + [DecoratorNames.PARAM]?: arkts.AnnotationUsage; + [DecoratorNames.EVENT]?: arkts.AnnotationUsage; + [DecoratorNames.REQUIRE]?: arkts.AnnotationUsage; + [DecoratorNames.CONSUMER]?: arkts.AnnotationUsage; + [DecoratorNames.PROVIDER]?: arkts.AnnotationUsage; +} + +export class StructPropertyAnnotationRecord extends BaseAnnotationRecord< + StructPropertyAnnotations, + StructPropertyAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = true; // TODO: remove this line + this.annotationNames = [ + DecoratorNames.STATE, + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP, + DecoratorNames.LINK, + DecoratorNames.PROP, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.OBJECT_LINK, + DecoratorNames.WATCH, + DecoratorNames.BUILDER_PARAM, + DecoratorNames.LOCAL_STORAGE_PROP, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.PROP_REF, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL, + DecoratorNames.PARAM, + DecoratorNames.EVENT, + DecoratorNames.REQUIRE, + DecoratorNames.CONSUMER, + DecoratorNames.PROVIDER, + ]; + } + + updateAnnotationInfoByName( + info: StructPropertyAnnotationInfo, + name: string | undefined + ): StructPropertyAnnotationInfo { + if (!!name && this.annotationNames.includes(name)) { + info[`has${name}`] = true; + } + return info; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/base.ts b/arkui-plugins/collectors/ui-collectors/records/base.ts new file mode 100644 index 000000000..fff4152d4 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/base.ts @@ -0,0 +1,75 @@ +/* + * 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 arkts from '@koalaui/libarkts'; + +export interface RecordOptions { + shouldIgnoreDecl: boolean; +} + +export abstract class BaseRecord> { + protected info: T | undefined; + protected shouldIgnoreDecl: boolean; + + private _isChanged: boolean = false; + private _isCollected: boolean = false; + + constructor(options: RecordOptions) { + this.shouldIgnoreDecl = options.shouldIgnoreDecl; + } + + protected get isChanged(): boolean { + return this._isChanged; + } + + protected set isChanged(isChanged: boolean) { + this._isChanged = isChanged; + } + + get isCollected(): boolean { + return this._isCollected; + } + + getOptions(): RecordOptions { + return { + shouldIgnoreDecl: this.shouldIgnoreDecl + } + } + + toRecord(): T | undefined { + this.refresh(); + return this.info; + } + + collect(node: Node): void { + this.collectFromNode(node); + this.isChanged = true; + this._isCollected = true; + } + + refresh(): void { + if (!this.isChanged) { + return; + } + this.refreshOnce(); + this.isChanged = false; + } + + protected abstract collectFromNode(node: Node): void; + + protected abstract refreshOnce(): void; + + abstract toJSON(): T; +} \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/records/cache.ts b/arkui-plugins/collectors/ui-collectors/records/cache.ts new file mode 100644 index 000000000..2ea11e0b3 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/cache.ts @@ -0,0 +1,167 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseRecord } from './base'; +import { AstNodePointer } from 'common/safe-types'; + +/** + * Singleton LRU Cache implementation using Map's insertion order + * for efficient least-recently-used eviction. + */ +export class RecordCache>> { + private static instance: RecordCache>>; + private cache: Map; + private maxSize: number; + + private constructor(maxSize: number = 100) { + if (maxSize <= 0) { + throw new Error('Cache size must be positive'); + } + this.cache = new Map(); + this.maxSize = maxSize; + } + + /** + * Get the singleton instance of the cache + * @param maxSize Maximum number of items to store (default: 100) + * @returns The cache instance + */ + public static getInstance>>( + maxSize: number = 100 + ): RecordCache { + if (!this.instance) { + this.instance = new RecordCache(maxSize); + } else if (maxSize !== RecordCache.instance.maxSize) { + this.instance.resize(maxSize); + } + return this.instance as RecordCache; + } + + /** + * Get a value from the cache + * @param key Cache key + * @returns The cached value or undefined if not found + */ + public get(key: AstNodePointer): T | undefined { + const value = this.cache.get(key); + if (value !== undefined) { + // Refresh key by deleting and re-adding it + this.cache.delete(key); + this.cache.set(key, value); + } + return value; + } + + /** + * Set a value in the cache + * @param key Cache key + * @param value Value to cache + */ + public set(key: AstNodePointer, value: T): void { + if (this.cache.has(key)) { + // Refresh key by deleting it first + this.cache.delete(key); + } else if (this.cache.size >= this.maxSize) { + // Evict the first item (least recently used) + const firstKey = this.cache.keys().next().value; + if (firstKey !== undefined) { + this.cache.delete(firstKey); + } + } + this.cache.set(key, value); + } + + /** + * Check if a key exists in the cache + * @param key Cache key to check + * @returns True if the key exists + */ + public has(key: AstNodePointer): boolean { + return this.cache.has(key); + } + + /** + * Delete a key from the cache + * @param key Cache key to delete + * @returns True if the key was deleted + */ + public delete(key: AstNodePointer): boolean { + return this.cache.delete(key); + } + + /** + * Clear all items from the cache + */ + public clear(): void { + this.cache.clear(); + } + + /** + * Get the current number of items in the cache + * @returns Number of cached items + */ + public size(): number { + return this.cache.size; + } + + /** + * Get all cache keys (in order of most recently used) + * @returns Array of keys + */ + public keys(): string[] { + return Array.from(this.cache.keys()).reverse(); + } + + /** + * Get all cache values (in order of most recently used) + * @returns Array of values + */ + public values(): T[] { + return Array.from(this.cache.values()).reverse(); + } + + /** + * Get all cache entries (in order of most recently used) + * @returns Array of [key, value] pairs + */ + public entries(): [string, T][] { + return Array.from(this.cache.entries()).reverse(); + } + + /** + * Resize the cache (evicts LRU items if new size is smaller) + * @param newSize New maximum cache size + */ + public resize(newSize: number): void { + if (newSize <= 0) { + throw new Error('Cache size must be positive'); + } + + this.maxSize = newSize; + while (this.cache.size > this.maxSize) { + const firstKey = this.cache.keys().next().value!; + this.cache.delete(firstKey); + } + } + + /** + * Execute a function for each cache entry (from most to least recently used) + * @param callback Function to execute + */ + public forEach(callback: (value: T, key: AstNodePointer) => void): void { + this.entries().forEach(([key, value]) => callback(value, key)); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts b/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts new file mode 100644 index 000000000..568e655c2 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts @@ -0,0 +1,140 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { CallDeclAnnotationInfo, CallDeclAnnotationRecord, CallDeclAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { BuiltInNames } from '../../../common/predefines'; + +export type CallDeclInfo = AnnotationRecord & { + /** + * declaration node's name. + */ + declName?: string; + + /** + * declaration node's modifier flags. + */ + modifiers?: arkts.Es2pandaModifierFlags; + + /** + * the module name where the declaration node is from. + */ + moduleName?: string; + + /** + * whether the call has function with receiver. + */ + hasReceiver?: boolean; + + /** + * whether the declaration node is a class property. + */ + isDeclFromClassProperty?: boolean; + + /** + * whether the declaration node is a class method. + */ + isDeclFromMethod?: boolean; + + /** + * whether declaration node is a global function. + */ + isDeclFromFunction?: boolean; +}; + +export class CallDeclRecord extends BaseRecord { + private _annotationRecord: CallDeclAnnotationRecord; + + protected declName?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected moduleName?: string; + protected hasReceiver?: boolean; + protected isDeclFromClassProperty?: boolean; + protected isDeclFromMethod?: boolean; + protected isDeclFromFunction?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new CallDeclAnnotationRecord(options); + } + + private collectAnnotations(annotations: readonly arkts.AnnotationUsage[]): void { + for (const anno of annotations) { + this._annotationRecord.collect(anno); + } + } + + private collectFromClassProperty(node: arkts.ClassProperty): void { + if (!node.key || !arkts.isIdentifier(node.key)) { + return; + } + this.collectAnnotations(node.annotations); + this.declName = node.key.name; + this.modifiers = node.modifiers; + this.isDeclFromClassProperty = true; + } + + private collectFromMethod(node: arkts.MethodDefinition): void { + this.collectAnnotations(node.scriptFunction.annotations); + this.declName = node.name.name; + this.modifiers = node.modifiers; + this.hasReceiver = node.scriptFunction.hasReceiver; + if ( + !!node.parent && + arkts.isMethodDefinition(node.parent) && + node.parent.name.name === BuiltInNames.ETS_GLOBAL_CLASS + ) { + this.isDeclFromFunction = true; + } else { + this.isDeclFromMethod = true; + } + } + + protected collectFromNode(node: arkts.AstNode): void { + this.moduleName = arkts.getProgramFromAstNode(node)?.moduleName; + if (arkts.isClassProperty(node)) { + this.collectFromClassProperty(node); + } else if (arkts.isMethodDefinition(node)) { + this.collectFromMethod(node); + } + } + + protected refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.declName && { declName: this.declName }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): CallDeclInfo { + this.refresh(); + return { + ...(this.info?.declName && { declName: this.info.declName }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.moduleName && { moduleName: this.info.moduleName }), + ...(this.info?.isDeclFromClassProperty && { isDeclFromClassProperty: this.info.isDeclFromClassProperty }), + ...(this.info?.isDeclFromMethod && { isDeclFromMethod: this.info.isDeclFromMethod }), + ...(this.info?.isDeclFromFunction && { isDeclFromFunction: this.info.isDeclFromFunction }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/function-call.ts b/arkui-plugins/collectors/ui-collectors/records/function-call.ts new file mode 100644 index 000000000..478bc7d77 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/function-call.ts @@ -0,0 +1,324 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseRecord, RecordOptions } from './base'; +import { CallDeclInfo, CallDeclRecord } from './call-declaration'; +import { CustomComponentInfo, CustomComponentRecord } from './struct'; +import { RecordBuilder } from './record-builder'; +import { + checkIsCallNameFromBindable, + checkIsCallNameFromResource, + findRootCallee, + findRootCallObject, + getDeclFromArkUI, + getStructFromCall, +} from '../utils'; +import { AstNodePointer } from '../../../common/safe-types'; +import { ARKUI_IMPORT_PREFIX_NAMES, Dollars } from '../../../common/predefines'; +import { matchPrefix } from '../../../common/arkts-utils'; +import { DeclarationCollector } from '../../../common/declaration-collector'; + +export type CallInfo = CallDeclInfo & { + /** + * this call node pointer + */ + ptr?: AstNodePointer; + + /** + * this call name (i.e. callee must be an Identifier), e.g calls like `a[0]()` has no call name + */ + callName?: string; + + /** + * a list of call names start from the root call to this call (both inclusive) + */ + chainingCallNames?: string[]; + + /** + * whether this call is from current class's method or property + */ + isThis?: boolean; + + /** + * whether this call has trailing lambda argument + */ + isTrailingCall?: boolean; + + /** + * whether this call is `$$()` bindable call + */ + isBindableCall?: Dollars.DOLLAR_DOLLAR; + + /** + * whether bthis call is `$r()` or `$rawfile()` resource call + */ + isResourceCall?: Dollars.DOLLAR_RESOURCE | Dollars.DOLLAR_RAWFILE; + + /** + * call information from this call's root (e.g. `A.b().c()` has root call `b()`), call is root call if not exist + */ + rootCallInfo?: CallInfo; + + /** + * struct information from this call's object, call is not a struct call if not exist + */ + structDeclInfo?: CustomComponentInfo; + + /** + * struct information which contains this call, call is not in a struct if not exist + */ + fromStructInfo?: CustomComponentInfo; +}; + +export class CallRecord extends BaseRecord { + private _declRecord: CallDeclRecord; + private _structDeclRecord?: CustomComponentRecord; + private _fromStructRecord?: CustomComponentRecord; + + protected callName?: string; + protected ptr?: AstNodePointer; + protected isThis?: boolean; + protected isTrailingCall?: boolean; + protected isBindableCall?: Dollars.DOLLAR_DOLLAR; + protected isResourceCall?: Dollars.DOLLAR_RESOURCE | Dollars.DOLLAR_RAWFILE; + protected declInfo?: CallDeclInfo; + protected structDeclInfo?: CustomComponentInfo; + protected fromStructInfo?: CustomComponentInfo; + + private _rootCallObject?: arkts.Identifier | undefined; + private _rootCallee?: arkts.Identifier | undefined; + private _rootCallInfo?: CallInfo; + private _chainingCallNames?: string[]; + + constructor(options: RecordOptions) { + super(options); + this._declRecord = new CallDeclRecord(options); + } + + protected get rootCallInfo(): CallInfo | undefined { + return this._rootCallInfo; + } + + protected set rootCallInfo(rootCallInfo: CallInfo | undefined) { + if (this._rootCallInfo?.ptr !== rootCallInfo?.ptr) { + this._rootCallInfo = rootCallInfo; + this.isChanged = true; + } + } + + protected get chainingCallNames(): string[] | undefined { + return this._chainingCallNames; + } + + protected set chainingCallNames(chainingCallNames: string[] | undefined) { + this._chainingCallNames = chainingCallNames; + this.isChanged = true; + } + + private checkIsThisFromCallee(callee: arkts.Identifier | undefined): boolean { + if (!callee) { + return false; + } + if (!callee.parent || !arkts.isMemberExpression(callee.parent)) { + return false; + } + return callee.parent.object && arkts.isThisExpression(callee.parent.object); + } + + private collectFromDecl(decl: arkts.AstNode | undefined): void { + if (!decl) { + return; + } + this._declRecord.collect(decl); + } + + private collectStructDeclInfo(structNode: arkts.ClassDefinition | undefined): void { + if (!structNode || !structNode.parent || !arkts.isClassDeclaration(structNode.parent)) { + return; + } + const _record = RecordBuilder.build(CustomComponentRecord, structNode.parent, this.getOptions()); + this._structDeclRecord = _record; + if (!this._structDeclRecord.isCollected) { + this._structDeclRecord.collect(structNode.parent); + } + } + + private collectFromStructInfo(structNode: arkts.ClassDefinition | undefined): void { + if (!structNode || !structNode.parent || !arkts.isClassDeclaration(structNode.parent)) { + return; + } + const _record = RecordBuilder.build(CustomComponentRecord, structNode.parent, this.getOptions()); + this._fromStructRecord = _record; + if (!this._fromStructRecord.isCollected) { + this._fromStructRecord.collect(structNode.parent); + } + } + + private findStructDeclInfo(): void { + if (!!this.rootCallInfo?.structDeclInfo) { + this.structDeclInfo = this.rootCallInfo.structDeclInfo; + } else if (!this.structDeclInfo) { + const structNode = getStructFromCall(this._rootCallObject, this._rootCallee); + this.collectStructDeclInfo(structNode); + } + } + + private findFromStructInfo(): void { + if (!!this.rootCallInfo?.fromStructInfo) { + this.fromStructInfo = this.rootCallInfo.fromStructInfo; + } else if (!this.fromStructInfo) { + const structNode = this._rootCallee?.findOuterParent( + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DEFINITION + ); + this.collectFromStructInfo(structNode); + } + } + + private findResourceCall(decl: arkts.AstNode, declInfo: CallDeclInfo): void { + const name = declInfo.declName; + const moduleName = declInfo.moduleName; + if (!this.shouldIgnoreDecl && (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName))) { + return; + } + if (!name || !checkIsCallNameFromResource(name)) { + return; + } + this.isResourceCall = name; + DeclarationCollector.getInstance().collect(decl); + } + + private findBinableCall(decl: arkts.AstNode, declInfo: CallDeclInfo): void { + const name = declInfo.declName; + const moduleName = declInfo.moduleName; + if (!this.shouldIgnoreDecl && (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName))) { + return; + } + if (!name || !checkIsCallNameFromBindable(name)) { + return; + } + this.isBindableCall = name; + DeclarationCollector.getInstance().collect(decl); + } + + private findIsSpecialCall(decl?: arkts.AstNode): void { + const declInfo = this._declRecord.toRecord(); + if (!decl || !declInfo || !declInfo.declName) { + return; + } + this.findBinableCall(decl, declInfo); + this.findResourceCall(decl, declInfo); + } + + withRootCallee(rootCallee: arkts.Identifier | undefined): this { + this._rootCallee = rootCallee; + this.findStructDeclInfo(); + this.findFromStructInfo(); + return this; + } + + withRootCallObject(rootCallObject: arkts.Identifier | undefined): this { + this._rootCallObject = rootCallObject; + this.findStructDeclInfo(); + return this; + } + + withRootCallInfo(rootCallInfo: CallInfo): this { + this.rootCallInfo = rootCallInfo; + this.findStructDeclInfo(); + this.findFromStructInfo(); + return this; + } + + withChainingCallNames(chainingCallNames: string[]): this { + this.chainingCallNames = chainingCallNames; + return this; + } + + collectFromNode(node: arkts.CallExpression): void { + this.ptr = node.peer; + + const callee = node.expression; + this._rootCallObject = this._rootCallObject ?? findRootCallObject(callee); + this._rootCallee = this._rootCallee ?? findRootCallee(callee); + this.callName = this._rootCallee?.name; + this.isThis = this.checkIsThisFromCallee(this._rootCallee); + this.isTrailingCall = node.isTrailingCall; + this.findStructDeclInfo(); + this.findFromStructInfo(); + + const decl = arkts.getPeerIdentifierDecl(callee.peer); + this.collectFromDecl(decl); + this.findIsSpecialCall(decl); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const declRecord = this._declRecord.toRecord(); + const structDeclInfo = this.structDeclInfo ?? this._structDeclRecord?.toRecord(); + const fromStructInfo = this.fromStructInfo ?? this._fromStructRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(this.ptr && { ptr: this.ptr }), + ...(this.callName && { callName: this.callName }), + ...(this.chainingCallNames && { chainingCallNames: this.chainingCallNames }), + ...(this.isThis && { isThis: this.isThis }), + ...(this.isTrailingCall && { isTrailingCall: this.isTrailingCall }), + ...(declRecord && { ...declRecord }), + ...(this.rootCallInfo && { rootCallInfo: this.rootCallInfo }), + ...(structDeclInfo && { structDeclInfo }), + ...(fromStructInfo && { fromStructInfo }), + }; + this.info = currInfo; + } + + toRootCallJSON(): CallInfo | undefined { + if (!this.info || !this.info.rootCallInfo) { + return undefined; + } + const rootInfo = this.info.rootCallInfo; + return { + ...(rootInfo.callName && { callName: rootInfo.callName }), + ...(rootInfo.chainingCallNames && { chainingCallNames: rootInfo.chainingCallNames }), + ...(rootInfo.isThis && { isThis: rootInfo.isThis }), + ...(rootInfo.isTrailingCall && { isTrailingCall: rootInfo.isTrailingCall }), + ...(rootInfo.declName && { declName: rootInfo.declName }), + ...(rootInfo.modifiers && { modifiers: rootInfo.modifiers }), + ...(rootInfo.moduleName && { moduleName: rootInfo.moduleName }), + ...(rootInfo.isDeclFromClassProperty && { isDeclFromClassProperty: rootInfo.isDeclFromClassProperty }), + ...(rootInfo.isDeclFromMethod && { isDeclFromMethod: rootInfo.isDeclFromMethod }), + ...(rootInfo.isDeclFromFunction && { isDeclFromFunction: rootInfo.isDeclFromFunction }), + ...(rootInfo.annotationInfo && { annotationInfo: rootInfo.annotationInfo }), + }; + } + + toJSON(): CallInfo { + this.refresh(); + const declInfo = this._declRecord.toJSON(); + const rootCallInfo = this.toRootCallJSON(); + const structDeclInfo = this._structDeclRecord?.toJSON(); + const fromStructInfo = this._fromStructRecord?.toJSON(); + return { + ...(this.info?.callName && { callName: this.info.callName }), + ...(this.info?.chainingCallNames && { chainingCallNames: this.info.chainingCallNames }), + ...(this.info?.isThis && { isThis: this.info.isThis }), + ...(this.info?.isTrailingCall && { isTrailingCall: this.info.isTrailingCall }), + ...(declInfo && { ...declInfo }), + ...(rootCallInfo && { rootCallInfo }), + ...(structDeclInfo && { structDeclInfo }), + ...(fromStructInfo && { fromStructInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/function.ts b/arkui-plugins/collectors/ui-collectors/records/function.ts new file mode 100644 index 000000000..2e00b30f3 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/function.ts @@ -0,0 +1,87 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { FunctionAnnotationInfo, FunctionAnnotationRecord, FunctionAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { BuiltInNames } from '../../../common/predefines'; + +export type FunctionInfo = AnnotationRecord< + FunctionAnnotations, + FunctionAnnotationInfo +> & { + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; + isDecl?: boolean; + isGlobalInit?: boolean; + isGlobalMain?: boolean; +}; + +export class FunctionRecord extends BaseRecord { + private _annotationRecord: FunctionAnnotationRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected kind?: arkts.Es2pandaMethodDefinitionKind; + protected isDecl?: boolean; + protected isGlobalInit?: boolean; + protected isGlobalMain?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new FunctionAnnotationRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.name.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + this.isGlobalInit = this.name === BuiltInNames.GLOBAL_INIT_METHOD; + this.isGlobalMain = this.name === BuiltInNames.GLOBAL_MAIN_METHOD; + for (const anno of node.scriptFunction.annotations) { + this._annotationRecord.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.kind && { kind: this.kind }), + ...(this.isDecl && { isDecl: this.isDecl }), + ...(this.isGlobalInit && { isGlobalInit: this.isGlobalInit }), + ...(this.isGlobalMain && { isGlobalMain: this.isGlobalMain }), + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): FunctionInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.kind && { kind: this.info.kind }), + ...(this.info?.isDecl && { isDecl: this.info.isDecl }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/index.ts b/arkui-plugins/collectors/ui-collectors/records/index.ts new file mode 100644 index 000000000..c48cb8bd3 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/index.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +export * from './annotations'; +export * from './normal-class'; +export * from './normal-class-property'; +export * from './normal-class-method'; +export * from './normal-interface'; +export * from './normal-interface-property'; +export * from './struct'; +export * from './struct-property'; +export * from './struct-method'; +export * from './struct-interface'; +export * from './struct-interface-property'; +export * from './call-declaration'; +export * from './function'; +export * from './function-call'; +export * from './record-builder'; +export * from './cache'; \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts b/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts new file mode 100644 index 000000000..f1f6de124 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts @@ -0,0 +1,91 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseRecord, RecordOptions } from './base'; +import { NormalClassInfo, NormalClassRecord } from './normal-class'; +import { AnnotationRecord } from './annotations/base'; +import { + NormalClassMethodAnnotationInfo, + NormalClassMethodAnnotationRecord, + NormalClassMethodAnnotations, +} from './annotations'; + +export type NormalClassMethodInfo = AnnotationRecord & { + classInfo?: NormalClassInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; + isDecl?: boolean; +}; + +export interface NormalClassMethodRecordOptions extends RecordOptions { + classRecord?: NormalClassRecord; +} + +export class NormalClassMethodRecord extends BaseRecord { + private _annotationRecord: NormalClassMethodAnnotationRecord; + private _classRecord?: NormalClassRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected kind?: arkts.Es2pandaMethodDefinitionKind; + protected isDecl?: boolean; + + constructor(options: NormalClassMethodRecordOptions) { + super(options); + this._classRecord = options.classRecord; + this._annotationRecord = new NormalClassMethodAnnotationRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.name.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + for (const anno of node.scriptFunction.annotations) { + this._annotationRecord.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const classRecord = this._classRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.kind && { kind: this.kind }), + ...(this.isDecl && { isDecl: this.isDecl }), + ...(annotationRecord && { ...annotationRecord }), + ...(classRecord && { classInfo: classRecord }), + }; + this.info = currInfo; + } + + toJSON(): NormalClassMethodInfo { + this.refresh(); + const classInfo = this._classRecord?.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.kind && { kind: this.info.kind }), + ...(this.info?.isDecl && { isDecl: this.info.isDecl }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(classInfo && { classInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts b/arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts new file mode 100644 index 000000000..923c7cbd8 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts @@ -0,0 +1,88 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { + NormalClassPropertyAnnotationInfo, + NormalClassPropertyAnnotationRecord, + NormalClassPropertyAnnotations, +} from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { NormalClassInfo, NormalClassRecord } from './normal-class'; + +export type NormalClassPropertyInfo = AnnotationRecord< + NormalClassPropertyAnnotations, + NormalClassPropertyAnnotationInfo +> & { + classInfo?: NormalClassInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; +}; + +export interface NormalClassPropertyRecordOptions extends RecordOptions { + classRecord: NormalClassRecord; +} + +export class NormalClassPropertyRecord extends BaseRecord { + private _annotationRecord: NormalClassPropertyAnnotationRecord; + private _classRecord: NormalClassRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + + constructor(options: NormalClassPropertyRecordOptions) { + super(options); + this._classRecord = options.classRecord; + this._annotationRecord = new NormalClassPropertyAnnotationRecord(options); + } + + collectFromNode(node: arkts.ClassProperty): void { + const key: arkts.Expression | undefined = node.key; + if (!key || !arkts.isIdentifier(key)) { + return; + } + this.name = key.name; + this.modifiers = node.modifiers; + for (const anno of node.annotations) { + this._annotationRecord.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const classRecord = this._classRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(annotationRecord && { ...annotationRecord }), + ...(classRecord && { classInfo: classRecord }), + }; + this.info = currInfo; + } + + toJSON(): NormalClassPropertyInfo { + this.refresh(); + const classInfo = this._classRecord.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(classInfo && { classInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/normal-class.ts b/arkui-plugins/collectors/ui-collectors/records/normal-class.ts new file mode 100644 index 000000000..8daf06f18 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/normal-class.ts @@ -0,0 +1,97 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { NormalClassAnnotationInfo, NormalClassAnnotationRecord, NormalClassAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { RecordCache } from './cache'; +import { BuiltInNames } from '../../../common/predefines'; +import { AstNodePointer } from '../../../common/safe-types'; + +export type NormalClassInfo = AnnotationRecord & { + /** + * class defintion node's pointer. + */ + definitionPtr?: AstNodePointer; + + /** + * class name. + */ + name?: string; + + /** + * whether this class is declared. + */ + isDecl?: boolean; + + /** + * whether this class is ETSGLOBAL class. + */ + isETSGlobal?: boolean; +}; + +export class NormalClassRecord extends BaseRecord { + private _annotationRecord: NormalClassAnnotationRecord; + + protected definitionPtr?: AstNodePointer; + protected name?: string; + protected isDecl?: boolean; + protected isETSGlobal?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new NormalClassAnnotationRecord(options); + } + + collectFromNode(node: arkts.ClassDeclaration): void { + const definition: arkts.ClassDefinition | undefined = node.definition; + if (!definition || !definition?.ident?.name) { + return; + } + this.name = definition.ident.name; + this.definitionPtr = definition.peer; + this.isETSGlobal = this.name === BuiltInNames.ETS_GLOBAL_CLASS; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + for (const anno of definition.annotations) { + this._annotationRecord.collect(anno); + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.isDecl && { isDecl: this.isDecl }), + ...(this.isETSGlobal && { isETSGlobal: this.isETSGlobal }), + ...(this.definitionPtr && { definitionPtr: this.definitionPtr }), + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): NormalClassInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.isDecl && { isDecl: this.info.isDecl }), + ...(this.isETSGlobal && { isETSGlobal: this.isETSGlobal }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts b/arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts new file mode 100644 index 000000000..43bd7c03a --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts @@ -0,0 +1,89 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { + NormalInterfacePropertyAnnotationInfo, + NormalInterfacePropertyAnnotationRecord, + NormalInterfacePropertyAnnotations, +} from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { NormalInterfaceInfo, NormalInterfaceRecord } from './normal-interface'; + +export type NormalInterfacePropertyInfo = AnnotationRecord< + NormalInterfacePropertyAnnotations, + NormalInterfacePropertyAnnotationInfo +> & { + interfaceInfo?: NormalInterfaceInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; +}; + +export interface NormalInterfacePropertyRecordOptions extends RecordOptions { + interfaceRecord: NormalInterfaceRecord; +} + +export class NormalInterfacePropertyRecord extends BaseRecord { + private _annotationRecord: NormalInterfacePropertyAnnotationRecord; + private _interfaceRecord: NormalInterfaceRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected kind?: arkts.Es2pandaMethodDefinitionKind; + + constructor(options: NormalInterfacePropertyRecordOptions) { + super(options); + this._interfaceRecord = options.interfaceRecord; + this._annotationRecord = new NormalInterfacePropertyAnnotationRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.name.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + for (const anno of node.scriptFunction.annotations) { + this._annotationRecord.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const interfaceRecord = this._interfaceRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.kind && { kind: this.kind }), + ...(annotationRecord && { ...annotationRecord }), + ...(interfaceRecord && { interfaceInfo: interfaceRecord }), + }; + this.info = currInfo; + } + + toJSON(): NormalInterfacePropertyInfo { + this.refresh(); + const interfaceInfo = this._interfaceRecord.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.kind && { kind: this.info.kind }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(interfaceInfo && { interfaceInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/normal-interface.ts b/arkui-plugins/collectors/ui-collectors/records/normal-interface.ts new file mode 100644 index 000000000..729be1798 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/normal-interface.ts @@ -0,0 +1,53 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseRecord, RecordOptions } from './base'; + +export type NormalInterfaceInfo = { + name?: string; +}; + +export class NormalInterfaceRecord extends BaseRecord { + protected name?: string; + + constructor(options: RecordOptions) { + super(options); + } + + collectFromNode(node: arkts.TSInterfaceDeclaration): void { + const interfaceBody: arkts.TSInterfaceBody | undefined = node.body; + if (!interfaceBody || !node.id?.name) { + return; + } + this.name = node.id.name; + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + } + this.info = currInfo; + } + + toJSON(): NormalInterfaceInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + } + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/record-builder.ts b/arkui-plugins/collectors/ui-collectors/records/record-builder.ts new file mode 100644 index 000000000..8af86e11f --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/record-builder.ts @@ -0,0 +1,45 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseRecord, RecordOptions } from './base'; +import { RecordCache } from './cache'; +import { AstNodePointer } from 'common/safe-types'; + +function getOrPut< + T extends BaseRecord>, + U extends RecordOptions = RecordOptions +>(key: AstNodePointer, options: U, create: (options: U) => T): T { + if (RecordCache.getInstance().has(key)) { + return RecordCache.getInstance().get(key)!; + } + const newRecord = create(options); + RecordCache.getInstance().set(key, newRecord); + return newRecord; +} + +export class RecordBuilder { + static build>, T extends RecordOptions = RecordOptions>( + Record: { new (options: T): V }, + node: U, + options: T + ): V { + return getOrPut(node.peer, options, (options: T) => new Record(options)); + } + + static reset(): void { + RecordCache.getInstance().clear(); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts b/arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts new file mode 100644 index 000000000..ca3012971 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts @@ -0,0 +1,90 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { StructPropertyAnnotationInfo, StructPropertyAnnotationRecord, StructPropertyAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { CustomComponentInterfaceInfo, CustomComponentInterfaceRecord } from './struct-interface'; +import { RecordCache } from './cache'; + +export type CustomComponentInterfacePropertyInfo = AnnotationRecord< + StructPropertyAnnotations, + StructPropertyAnnotationInfo +> & { + interfaceInfo?: CustomComponentInterfaceInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; +}; + +export interface CustomComponentInterfacePropertyRecordOptions extends RecordOptions { + interfaceRecord?: CustomComponentInterfaceRecord; +} + +export class CustomComponentInterfacePropertyRecord extends BaseRecord< + arkts.MethodDefinition, + CustomComponentInterfacePropertyInfo +> { + private _annotationRecord: StructPropertyAnnotationRecord; + private _interfaceRecord?: CustomComponentInterfaceRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected kind?: arkts.Es2pandaMethodDefinitionKind; + + constructor(options: CustomComponentInterfacePropertyRecordOptions) { + super(options); + this._interfaceRecord = options.interfaceRecord; + this._annotationRecord = new StructPropertyAnnotationRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.name.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + for (const anno of node.scriptFunction.annotations) { + this._annotationRecord.collect(anno); + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const interfaceRecord = this._interfaceRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.kind && { kind: this.kind }), + ...(annotationRecord && { ...annotationRecord }), + ...(interfaceRecord && { interfaceInfo: interfaceRecord }), + }; + this.info = currInfo; + } + + toJSON(): CustomComponentInterfacePropertyInfo { + this.refresh(); + const interfaceInfo = this._interfaceRecord?.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.kind && { kind: this.info.kind }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(interfaceInfo && { interfaceInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts b/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts new file mode 100644 index 000000000..83bdd9ac5 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts @@ -0,0 +1,66 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { CustomComponentAnnotationRecord, CustomComponentAnnotations, StructAnnotationInfo } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { RecordCache } from './cache'; + +export type CustomComponentInterfaceInfo = AnnotationRecord & { + name?: string; +}; + +export class CustomComponentInterfaceRecord extends BaseRecord { + private _annotationRecord: CustomComponentAnnotationRecord; + + protected name?: string; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new CustomComponentAnnotationRecord(options); + } + + collectFromNode(node: arkts.TSInterfaceDeclaration): void { + const interfaceBody: arkts.TSInterfaceBody | undefined = node.body; + if (!interfaceBody || !node.id?.name) { + return; + } + this.name = node.id.name; + for (const anno of node.annotations) { + this._annotationRecord.collect(anno); + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(annotationRecord && { ...annotationRecord }) + } + this.info = currInfo; + } + + toJSON(): CustomComponentInterfaceInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + } + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/struct-method.ts b/arkui-plugins/collectors/ui-collectors/records/struct-method.ts new file mode 100644 index 000000000..28804dc5b --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/struct-method.ts @@ -0,0 +1,95 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { StructMethodAnnotationInfo, StructMethodAnnotationRecord, StructMethodAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { CustomComponentRecord, CustomComponentInfo } from './struct'; +import { CustomComponentNames } from '../../../common/predefines'; +import { RecordCache } from './cache'; + +export type StructMethodInfo = AnnotationRecord & { + structInfo?: CustomComponentInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; + isDecl?: boolean; + isCtor?: boolean; +}; + +export interface StructMethodRecordOptions extends RecordOptions { + structRecord?: CustomComponentRecord; +} + +export class StructMethodRecord extends BaseRecord { + private _annotationRecord: StructMethodAnnotationRecord; + private _structRecord?: CustomComponentRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + protected kind?: arkts.Es2pandaMethodDefinitionKind; + protected isDecl?: boolean; + protected isCtor?: boolean; + + constructor(options: StructMethodRecordOptions) { + super(options); + this._structRecord = options.structRecord; + this._annotationRecord = new StructMethodAnnotationRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.name.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + this.isCtor = this.name === CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI; + for (const anno of node.scriptFunction.annotations) { + this._annotationRecord.collect(anno); + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const structRecord = this._structRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.kind && { kind: this.kind }), + ...(this.isDecl && { isDecl: this.isDecl }), + ...(this.isCtor && { isCtor: this.isCtor }), + ...(annotationRecord && { ...annotationRecord }), + ...(structRecord && { structInfo: structRecord }), + }; + this.info = currInfo; + } + + toJSON(): StructMethodInfo { + this.refresh(); + const structInfo = this._structRecord?.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.kind && { kind: this.info.kind }), + ...(this.info?.isDecl && { isDecl: this.info.isDecl }), + ...(this.info?.isCtor && { isCtor: this.info.isCtor }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(structInfo && { structInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/struct-property.ts b/arkui-plugins/collectors/ui-collectors/records/struct-property.ts new file mode 100644 index 000000000..ff1d698ad --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/struct-property.ts @@ -0,0 +1,83 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { StructPropertyAnnotationInfo, StructPropertyAnnotationRecord, StructPropertyAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { CustomComponentRecord, CustomComponentInfo } from './struct'; +import { RecordCache } from './cache'; + +export type StructPropertyInfo = AnnotationRecord & { + structInfo?: CustomComponentInfo; + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; +}; + +export interface StructPropertyRecordOptions extends RecordOptions { + structRecord: CustomComponentRecord; +} + +export class StructPropertyRecord extends BaseRecord { + private _annotationRecord: StructPropertyAnnotationRecord; + private _structRecord: CustomComponentRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + + constructor(options: StructPropertyRecordOptions) { + super(options); + this._structRecord = options.structRecord; + this._annotationRecord = new StructPropertyAnnotationRecord(options); + } + + collectFromNode(node: arkts.ClassProperty): void { + const key: arkts.Expression | undefined = node.key; + if (!key || !arkts.isIdentifier(key)) { + return; + } + this.name = key.name; + this.modifiers = node.modifiers; + for (const anno of node.annotations) { + this._annotationRecord.collect(anno); + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const structRecord = this._structRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(annotationRecord && { ...annotationRecord }), + ...(structRecord && { structInfo: structRecord }), + }; + this.info = currInfo; + } + + toJSON(): StructPropertyInfo { + this.refresh(); + const structInfo = this._structRecord.toJSON(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + ...(structInfo && { structInfo }), + }; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/records/struct.ts b/arkui-plugins/collectors/ui-collectors/records/struct.ts new file mode 100644 index 000000000..c23b0f786 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/records/struct.ts @@ -0,0 +1,93 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { CustomComponentAnnotationRecord, CustomComponentAnnotations, StructAnnotationInfo } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { checkIsCustomComponentDeclaredClass, checkIsStructFromNode } from '../utils'; +import { AstNodePointer } from '../../../common/safe-types'; +import { RecordCache } from './cache'; + +export type CustomComponentInfo = AnnotationRecord & { + /** + * class defintion node's pointer. + */ + definitionPtr?: AstNodePointer; + + /** + * struct name, or declared `CustomComponent` etcs. name in header files. + */ + name?: string; + + /** + * whether this struct or `CustomComponent` class is declared. + */ + isDecl?: boolean; +}; + +export class CustomComponentRecord extends BaseRecord { + private _annotationRecord: CustomComponentAnnotationRecord; + + protected definitionPtr?: AstNodePointer; + protected name?: string; + protected isDecl?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new CustomComponentAnnotationRecord(options); + } + + collectFromNode(node: arkts.ClassDeclaration): void { + const definition: arkts.ClassDefinition | undefined = node.definition; + if (!definition || !definition?.ident?.name) { + return; + } + this.name = definition.ident.name; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + if (checkIsCustomComponentDeclaredClass(definition, this.isDecl)) { + return; + } + if (checkIsStructFromNode(node)) { + for (const anno of definition.annotations) { + this._annotationRecord.collect(anno); + } + this.definitionPtr = definition.peer; + } + RecordCache.getInstance().set(node.peer, this); + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.isDecl && { isDecl: this.isDecl }), + ...(this.definitionPtr && { definitionPtr: this.definitionPtr }), + ...(annotationRecord && { ...annotationRecord }) + } + this.info = currInfo; + } + + toJSON(): CustomComponentInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.isDecl && { isDecl: this.info.isDecl }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + } + } +} diff --git a/arkui-plugins/collectors/ui-collectors/shared-types.ts b/arkui-plugins/collectors/ui-collectors/shared-types.ts new file mode 100644 index 000000000..c0625bb4b --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/shared-types.ts @@ -0,0 +1,27 @@ +/* + * 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 { VisitorOptions } from "../../common/abstract-visitor"; +import { AstNodePointer } from "../../common/safe-types"; +import { CustomComponentInfo, StructMethodInfo, StructPropertyInfo } from "./records"; + +export interface UICollectMetadata extends VisitorOptions { + shouldIgnoreDecl: boolean; +} + +export interface StructCollectorInfo extends CustomComponentInfo { + propertyInfoMap: Record; + methodInfoMap: Record; +} \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/struct-collector.ts b/arkui-plugins/collectors/ui-collectors/struct-collector.ts new file mode 100644 index 000000000..8e22f31ca --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/struct-collector.ts @@ -0,0 +1,157 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { + CustomComponentRecord, + StructMethodInfo, + StructMethodRecord, + StructPropertyInfo, + StructPropertyRecord, +} from './records'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { BuilderLambdaNames, CustomComponentNames, NodeCacheNames } from '../../common/predefines'; +import { AstNodePointer } from '../../common/safe-types'; +import { StructMethodValidator, StructPropertyValidator, ValidatorBuilder } from './validators'; + +export interface StructCollectorOptions extends VisitorOptions { + structRecord: CustomComponentRecord; + shouldIgnoreDecl?: boolean; +} + +export class StructCollector extends AbstractVisitor { + private _structRecord: CustomComponentRecord; + private _disableCollectProperty: boolean = false; + private _shouldCollectProperty: boolean = true; + private _properties: Record = {}; + private _methods: Record = {}; + + public shouldIgnoreDecl: boolean; + + constructor(options: StructCollectorOptions) { + super(options); + this._structRecord = options.structRecord; + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + } + + get propertyInfoMap(): Record { + return this._properties; + } + + get methodInfoMap(): Record { + return this._methods; + } + + private get shouldCollectProperty(): boolean { + if (this._disableCollectProperty) { + return false; + } + return this._shouldCollectProperty; + } + + private set shouldCollectProperty(newValue: boolean) { + if (this._disableCollectProperty) { + return; + } + this._shouldCollectProperty = newValue; + } + + private canCollectMethodFromInfo(info: StructMethodInfo): boolean { + if (!!info.isDecl && info.isCtor) { + return true; + } + if (info.isDecl && info.name === BuilderLambdaNames.ORIGIN_METHOD_NAME) { + return true; + } + if (info.name === CustomComponentNames.COMPONENT_BUILD_ORI) { + return true; + } + if (!!info.annotationInfo && Object.keys(info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private collectProperty(node: arkts.ClassProperty): void { + const propertyRecord = new StructPropertyRecord({ + structRecord: this._structRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + propertyRecord.collect(node); + + const propertyInfo = propertyRecord.toRecord(); + if (!propertyInfo) { + return; + } + // TODO: call ui-checker + // TODO: collect property info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, propertyRecord.toJSON()); + this._properties[node.peer] = propertyInfo; + + // console.log('[STRUCT PROPERTY] node: ', node.dumpSrc()); + // console.log('[STRUCT PROPERTY] propertyInfo: ', propertyInfo); + ValidatorBuilder.build(StructPropertyValidator).checkIsViolated(node, propertyInfo); + } + + private collectMethod(node: arkts.MethodDefinition): void { + const methodRecord = new StructMethodRecord({ + structRecord: this._structRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + methodRecord.collect(node); + + const methodInfo = methodRecord.toRecord(); + if (!methodInfo) { + return; + } + // TODO: call ui-checker + if (this.canCollectMethodFromInfo(methodInfo)) { + // TODO: collect method info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + this._methods[node.peer] = methodInfo; + } + // console.log('[STRUCT METHOD] node: ', node.dumpSrc()); + // console.log('[STRUCT METHOD] methodInfo: ', methodInfo); + ValidatorBuilder.build(StructMethodValidator).checkIsViolated(node, methodInfo); + } + + disableCollectProperty(): this { + this._disableCollectProperty = true; + return this; + } + + enableCollectProperty(): this { + this._disableCollectProperty = false; + return this; + } + + reset(): void { + this._shouldCollectProperty = true; + this._disableCollectProperty = false; + this._properties = {}; + this._methods = {}; + } + + visitor(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + node.definition?.body.forEach((st) => { + if (arkts.isClassProperty(st) && this.shouldCollectProperty) { + this.collectProperty(st); + } else if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts b/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts new file mode 100644 index 000000000..f62b214d3 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts @@ -0,0 +1,73 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { + CustomComponentInterfacePropertyInfo, + CustomComponentInterfacePropertyRecord, + CustomComponentInterfaceRecord, +} from './records'; +import { NodeCacheNames } from '../../common/predefines'; + +export interface StructInterfaceCollectorOptions extends VisitorOptions { + interfaceRecord: CustomComponentInterfaceRecord; + shouldIgnoreDecl?: boolean; +} + +export class StructInterfaceCollector extends AbstractVisitor { + private _interfaceRecord: CustomComponentInterfaceRecord; + public shouldIgnoreDecl: boolean; + + constructor(options: StructInterfaceCollectorOptions) { + super(options); + this._interfaceRecord = options.interfaceRecord; + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + } + + private canCollectMethodFromInfo(info: CustomComponentInterfacePropertyInfo): boolean { + if (!!info.annotationInfo && Object.keys(info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private collectMethod(node: arkts.MethodDefinition): void { + const methodRecord = new CustomComponentInterfacePropertyRecord({ + interfaceRecord: this._interfaceRecord, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + methodRecord.collect(node); + + const methodInfo = methodRecord.toRecord(); + if (!methodInfo) { + return; + } + if (this.canCollectMethodFromInfo(methodInfo)) { + // TODO: collect method info to cache + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + // console.log("[STRUCT INTERFACE METHOD] node: ", node.dumpSrc()); + } + } + + visitor(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + node.body?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/ui-visitor.ts b/arkui-plugins/collectors/ui-collectors/ui-visitor.ts new file mode 100644 index 000000000..416b5d34b --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/ui-visitor.ts @@ -0,0 +1,57 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { findAndCollectUINodeInPostOrder, findAndCollectUINodeInPreOrder } from './factory'; +import { UICollectMetadata } from './shared-types'; +import { CallRecordCollector } from './call-record-collector'; +import { ValidatorBuilder } from './validators'; +import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { LogCollector } from '../../common/log-collector'; + +export interface UIVisitorOptions extends VisitorOptions { + shouldIgnoreDecl?: boolean; +} + +export class UIVisitor extends AbstractVisitor { + private shouldIgnoreDecl?: boolean; + + constructor(options?: UIVisitorOptions) { + super(options); + this.shouldIgnoreDecl = true; // options?.shouldIgnoreDecl; + } + + reset(): void { + CallRecordCollector.getInstance(this.getMetadata()).reset(); + LogCollector.getInstance().reset(); + ValidatorBuilder.reset(); + } + + getMetadata(): UICollectMetadata { + return { + isExternal: this.isExternal, + externalSourceName: this.externalSourceName, + program: this.program, + shouldIgnoreDecl: this.shouldIgnoreDecl ?? false, + } + } + + visitor(node: arkts.AstNode): arkts.AstNode { + findAndCollectUINodeInPreOrder(node, this.getMetadata()); + const newNode = this.visitEachChild(node); + findAndCollectUINodeInPostOrder(newNode, this.getMetadata()); + return newNode; + } +} diff --git a/arkui-plugins/collectors/ui-collectors/utils.ts b/arkui-plugins/collectors/ui-collectors/utils.ts new file mode 100644 index 000000000..293218225 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/utils.ts @@ -0,0 +1,180 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { matchPrefix } from '../../common/arkts-utils'; +import { DeclarationCollector } from '../../common/declaration-collector'; +import { + CustomComponentNames, + ARKUI_IMPORT_PREFIX_NAMES, + ArkUIDeclInterfaceNames, + BuiltInNames, + BuilderLambdaNames, + Dollars, + StateManagementTypes, +} from '../../common/predefines'; +import { CustomComponentInfo, CustomComponentInterfaceInfo, NormalClassInfo, NormalInterfaceInfo } from './records'; + +export function findRootCallee(callee: arkts.AstNode | undefined): arkts.Identifier | undefined { + if (!callee) { + return undefined; + } + if (arkts.isIdentifier(callee)) { + return callee; + } + if (arkts.isMemberExpression(callee)) { + return findRootCallee(callee.property); + } + if (arkts.isTSAsExpression(callee)) { + return findRootCallee(callee.expr); + } + if (arkts.isTSNonNullExpression(callee)) { + return findRootCallee(callee.expr); + } + return undefined; +} + +export function findRootCallObject(callee: arkts.AstNode | undefined): arkts.Identifier | undefined { + if (!callee) { + return undefined; + } + if (arkts.isIdentifier(callee)) { + return callee; + } + if (arkts.isMemberExpression(callee)) { + return findRootCallee(callee.object); + } + if (arkts.isTSAsExpression(callee)) { + return findRootCallee(callee.expr); + } + if (arkts.isTSNonNullExpression(callee)) { + return findRootCallee(callee.expr); + } + return undefined; +} + +export function getAnnotationName(anno: arkts.AnnotationUsage, ignoreDecl?: boolean): string | undefined { + if (!anno.expr || !arkts.isIdentifier(anno.expr)) { + return undefined; + } + if (!ignoreDecl && !getDeclFromArkUI(anno.expr)) { + return undefined; + } + return anno.expr.name; +} + +export function getDeclFromArkUI( + node: arkts.AstNode, + matchSourcePrefix: (string | RegExp)[] = ARKUI_IMPORT_PREFIX_NAMES +): arkts.AstNode | undefined { + const decl = arkts.getPeerIdentifierDecl(node.peer); + if (!decl) { + return undefined; + } + const moduleName: string | undefined = arkts.getProgramFromAstNode(decl)?.moduleName; + if (!moduleName || !matchPrefix(matchSourcePrefix, moduleName)) { + return undefined; + } + DeclarationCollector.getInstance().collect(decl); + return decl; +} + +export function formatBuiltInImplementedPropertyName(name: string): string { + return name.slice(BuiltInNames.IMPLEMENT_PROPETY_PREFIX.length); +} + +export function getStructFromCall( + callObject: arkts.Identifier | undefined, + callee: arkts.Identifier | undefined +): arkts.ClassDefinition | undefined { + if (!callObject || !callee) { + return undefined; + } + if (callee.name !== BuilderLambdaNames.ORIGIN_METHOD_NAME) { + return undefined; + } + const decl = arkts.getPeerIdentifierDecl(callObject.peer); + if (!decl || !arkts.isClassDefinition(decl) || !arkts.classDefinitionIsFromStructConst(decl) || !decl.ident) { + return undefined; + } + return decl; +} + +export function checkIsCallNameFromResource(name: string): name is (Dollars.DOLLAR_RESOURCE | Dollars.DOLLAR_RAWFILE) { + return name === Dollars.DOLLAR_RESOURCE || name === Dollars.DOLLAR_RAWFILE; +} + +export function checkIsCallNameFromBindable(name: string): name is Dollars.DOLLAR_DOLLAR { + return name === Dollars.DOLLAR_DOLLAR; +} + +export function checkIsNameStartWithBackingField(node: arkts.AstNode | undefined): boolean { + if (!node || !arkts.isIdentifier(node)) { + return false; + } + return node.name.startsWith(StateManagementTypes.BACKING); +} + +export function checkIsStructFromNode(node: arkts.AstNode): boolean { + if (arkts.isStructDeclaration(node)) { + return true; + } + if ( + arkts.isClassDeclaration(node) && + !!node.definition && + arkts.classDefinitionIsFromStructConst(node.definition) + ) { + return true; + } + return false; +} + +export function checkIsCustomComponentDeclaredClass(node: arkts.ClassDefinition, isDecl?: boolean): boolean { + if (!node.ident) { + return false; + } + let info: CustomComponentInfo = { name: node.ident.name, isDecl }; + return checkIsCustomComponentDeclaredClassFromInfo(info); +} + +export function checkIsCustomComponentFromInfo( + info: CustomComponentInfo | CustomComponentInterfaceInfo | undefined +): boolean { + const annotationInfo = info?.annotationInfo ?? {}; + return !!annotationInfo.hasComponent || !!annotationInfo.hasComponentV2 || !!annotationInfo.hasCustomDialog; +} + +export function checkIsCustomComponentDeclaredClassFromInfo(info: CustomComponentInfo | undefined): boolean { + if (!info || !info.isDecl) { + return false; + } + return ( + info?.name === CustomComponentNames.COMPONENT_CLASS_NAME || + info?.name === CustomComponentNames.COMPONENT_V2_CLASS_NAME + ); +} + +export function checkIsObservedClassFromInfo(info: NormalClassInfo | undefined): boolean { + const annotationInfo = info?.annotationInfo ?? {}; + return !!annotationInfo.hasObserved || !!annotationInfo.hasObservedV2; +} + +export function checkIsETSGlobalClassFromInfo(info: NormalClassInfo | undefined): boolean { + return !!info?.isETSGlobal; +} + +export function checkIsCommonMethodInterfaceFromInfo(info: NormalInterfaceInfo | undefined): boolean { + return info?.name === ArkUIDeclInterfaceNames.COMMON_METHOD; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/base.ts b/arkui-plugins/collectors/ui-collectors/validators/base.ts new file mode 100644 index 000000000..e186a093a --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/base.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 * as arkts from '@koalaui/libarkts'; +import { LogCollector, LogInfo, SuggestionOptions } from '../../../common/log-collector'; + +export interface Validator { + checkIsViolated(node: TargetNode, metadata?: ContextMetadata): void; + collectContext(context: ContextMetadata): this; + reset(): void; +} + +export abstract class BaseValidator implements Validator { + protected context?: R; + + reset(): void { + this.context = undefined; + } + + checkIsViolated(node: T, metadata?: R | undefined): void { + if (!!metadata) { + this.collectContext(metadata); + } + this.reportIfViolated(node); + } + + collectContext(context: R): this { + this.context = context; + return this; + } + + protected report(logInfo: LogInfo): void { + // console.log('[VALIDATOR] report: ', formatReport(logInfo)); + LogCollector.getInstance().collectLogInfo(logInfo); + } + + abstract reportIfViolated(node: T): void; +} + +// TODO: remove this +function formatReport(logInfo: LogInfo): string { + const node = logInfo.node.dumpSrc(); + return JSON.stringify( + { + node, + level: logInfo.level, + message: logInfo.message, + args: logInfo.args, + suggestion: formatSuggestion(logInfo.suggestion), + code: logInfo.code, + }, + null, + 2 + ); +} + +// TODO: remove this +function formatSuggestion(suggestion: SuggestionOptions | undefined): Object | undefined { + if (!suggestion) { + return undefined; + } + const startRange = `(${suggestion.range[0].index()}, ${suggestion.range[0].line()})`; + const endRange = `(${suggestion.range[1].index()}, ${suggestion.range[1].line()})`; + const range = `${startRange} - ${endRange}`; + return { code: suggestion.code, range, args: suggestion.args }; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/cache.ts b/arkui-plugins/collectors/ui-collectors/validators/cache.ts new file mode 100644 index 000000000..c66b85a84 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/cache.ts @@ -0,0 +1,33 @@ +/* + * 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 { Validator } from "./base"; + +const cache = new Map(); + +export function getOrPut(key: string, create: () => Validator): Validator { + if (cache.has(key)) { + return cache.get(key)!; + } + + const newValidator = create(); + cache.set(key, newValidator); + return newValidator; +} + +export function clearValidatorCache(): void { + Array.from(cache.values()).forEach((validator) => validator.reset()); + cache.clear(); +} \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/validators/index.ts b/arkui-plugins/collectors/ui-collectors/validators/index.ts new file mode 100644 index 000000000..56c26b9d1 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/index.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +export * from './struct-call-validator'; +export * from './struct-property-validator'; +export * from './struct-method-validator'; +export * from './normal-class-method-validator'; +export * from './normal-class-property-validator'; +export * from './validator-builder'; \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts b/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts new file mode 100644 index 000000000..a104fa0ff --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts @@ -0,0 +1,33 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { NormalClassMethodInfo } from '../records'; +import { checkComputedDecorator, checkConsumerProviderDecorator } from './rules'; + +export class NormalClassMethodValidator extends BaseValidator { + reportIfViolated(node: arkts.MethodDefinition): void { + const metadata = this.context ?? {}; + if (!metadata.classInfo?.definitionPtr) { + return; + } + + checkConsumerProviderDecorator.bind(this)(node); + + const classNode = arkts.classByPeer(metadata.classInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, classNode); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts b/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts new file mode 100644 index 000000000..87471506c --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts @@ -0,0 +1,33 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { NormalClassPropertyInfo } from '../records'; +import { checkComputedDecorator, checkConsumerProviderDecorator } from './rules'; + +export class NormalClassPropertyValidator extends BaseValidator { + reportIfViolated(node: arkts.ClassProperty): void { + const metadata = this.context ?? {}; + if (!metadata.classInfo?.definitionPtr) { + return; + } + + checkConsumerProviderDecorator.bind(this)(node); + + const classNode = arkts.classByPeer(metadata.classInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, classNode); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts new file mode 100644 index 000000000..71d8a20a3 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts @@ -0,0 +1,63 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { isAnnotatedProperty } from '../utils'; +import { CallInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; + +/** + * 校验规则:自定义组件尾随闭包调用的场景,struct 声明中只能有1个BuilderParam + * + * 校验等级:error + */ +export function checkBuilderParam( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + if (!metadata.isTrailingCall) { + return; + } + + // 从struct 中获取被@BuilderParam 修饰的属性个数 + const properties: Array<{ property: arkts.ClassProperty; argc: number }> = []; + for (const member of struct.body) { + if (isAnnotatedProperty(member, DecoratorNames.BUILDER_PARAM)) { + properties.push({ + property: member, + argc: getBuilderParamTypeArgc(member), + }); + } + } + + // 如果@BuilderParam个数超过1个或者@BuilderParam修饰的函数类型有参数,那么就报错 + if (properties.length > 1 || (properties.length === 1 && properties[0].argc > 0)) { + const structName = struct.ident!.name; + this.report({ + node: struct.parent!, // Class Declaration has correct position information + level: LogType.ERROR, + message: `In the trailing lambda case, '${structName}' must have one and only one property decorated with @BuilderParam, and its @BuilderParam expects no parameter.`, + }); + } +} + +function getBuilderParamTypeArgc(property: arkts.ClassProperty): number { + if (!property.typeAnnotation || !arkts.isETSFunctionType(property.typeAnnotation)) { + return -1; + } + return property.typeAnnotation.params.length; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts new file mode 100644 index 000000000..b22387aa2 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts @@ -0,0 +1,51 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { isAnnotatedProperty } from '../utils'; +import { CallInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; + +/** + * 校验规则:当V2组件使用V1组件时,V1组件中不允许存在被`@Link`装饰的属性 + * + * 校验等级:error + */ +export function checkComponentLinkInit( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + const fromComponentV2: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasComponentV2; + const isComponentCall: boolean = !!metadata.structDeclInfo?.annotationInfo?.hasComponent; + if (!(fromComponentV2 && isComponentCall)) { + return; + } + + // 只要当前struct 中有被"@Link" 修饰的属性就报错 + for (const member of struct.body) { + if (isAnnotatedProperty(member, DecoratorNames.LINK)) { + const declaration = struct.parent!; // Class Declaration has correct position information + this.report({ + node: declaration, + level: LogType.ERROR, + message: `A V2 component cannot be used with any member property annotated by '@Link' in a V1 component.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(declaration)), + }); + } + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts new file mode 100644 index 000000000..b298aaaa5 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts @@ -0,0 +1,135 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { NormalClassRecord, RecordBuilder, StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; + +/** + * 校验规则:禁止在`@Component`中使用`@ObservedV2`装饰的类 + * + * 校验等级:error + */ +export function checkComponentV2MixUse( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.annotationInfo?.hasComponent) { + return; + } + + const v1Decorators = findStructPropertyV1DecoratorsFromInfo(metadata); + if (v1Decorators.length === 0) { + return; + } + let decl: arkts.AstNode | undefined; + let expr: arkts.Identifier | undefined; + expr = findTypeRefIdentFromType(classProperty.typeAnnotation); + if (!expr && checkIsNewClass(classProperty.value)) { + expr = findTypeRefIdentFromType(classProperty.value.getTypeRef); + } + if (!!expr) { + decl = arkts.getPeerIdentifierDecl(expr.peer); + } + if (!decl || !checkIsClassDef(decl) || !checkIsClassDecl(decl.parent)) { + return; + } + const classRecord = RecordBuilder.build(NormalClassRecord, decl.parent, { shouldIgnoreDecl: true }); // TODO: change back to false; + if (!classRecord.isCollected) { + classRecord.collect(decl.parent); + } + const classInfo = classRecord.toRecord(); + if (!classInfo?.annotationInfo?.hasObservedV2) { + return; + } + v1Decorators.forEach((info) => + this.report({ + node: info.annotation, + message: `The type of the ${info.name} property cannot be a class decorated with '@ObservedV2'.`, + level: LogType.ERROR, + }) + ); +} + +interface DecoratorInfo { + name: string; + annotation: arkts.AnnotationUsage; +} + +const v1ComponentDecorators: string[] = [ + DecoratorNames.STATE, + DecoratorNames.PROP_REF, + DecoratorNames.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL_STORAGE_LINK, +]; + +function findStructPropertyV1DecoratorsFromInfo(info: StructPropertyInfo): DecoratorInfo[] { + if (!info.annotationInfo || !info.annotations) { + return []; + } + return v1ComponentDecorators + .filter((name) => !!info.annotationInfo?.[`has${name}`]) + .map((name) => ({ + name, + annotation: info.annotations?.[name]!, + })); +} + +function checkIsClassDef(node: arkts.AstNode | undefined): node is arkts.ClassDefinition { + return !!node && arkts.isClassDefinition(node); +} + +function checkIsClassDecl(node: arkts.AstNode | undefined): node is arkts.ClassDeclaration { + return !!node && arkts.isClassDeclaration(node); +} + +function checkIsTypeRef(node: arkts.AstNode | undefined): node is arkts.ETSTypeReference { + return !!node && arkts.isETSTypeReference(node); +} + +function checkIsTypeRefPart(node: arkts.AstNode | undefined): node is arkts.ETSTypeReferencePart { + return !!node && arkts.isETSTypeReferencePart(node); +} + +function checkIsIdentifier(node: arkts.AstNode | undefined): node is arkts.Identifier { + return !!node && arkts.isIdentifier(node); +} + +function checkIsUnionType(node: arkts.AstNode | undefined): node is arkts.ETSUnionType { + return !!node && arkts.isETSUnionType(node); +} + +function checkIsNewClass(node: arkts.AstNode | undefined): node is arkts.ETSNewClassInstanceExpression { + return !!node && arkts.isETSNewClassInstanceExpression(node); +} + +function findTypeRefIdentFromType(node: arkts.AstNode | undefined): arkts.Identifier | undefined { + if (checkIsIdentifier(node)) { + return node; + } + if (checkIsTypeRef(node) && checkIsTypeRefPart(node.part) && checkIsIdentifier(node.part.name)) { + return node.part.name; + } + if (checkIsUnionType(node)) { + return node.types.map(findTypeRefIdentFromType).find((t) => !!t); + } + return undefined; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts new file mode 100644 index 000000000..08432e84d --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts @@ -0,0 +1,199 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { coerceToAstNode } from '../utils'; +import type { IntrinsicValidatorFunction, ModifiedValidatorFunction } from '../safe-types'; +import { + CallInfo, + CustomComponentInterfacePropertyRecord, + RecordBuilder, + StructMethodInfo, + StructPropertyInfo, +} from '../../records'; +import { checkIsNameStartWithBackingField } from '../../utils'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; + +/** + * 校验规则: + * 1. 确保成员属性或方法不能同时被多个内置装饰器(`@Local`, `@Param`, `@Event`)装饰; + * 2. 当用`@Param`装饰的变量没有被分配默认值时,它也必须用`@Require`装饰; + * 3. 在被`@ComponentV2`装饰的结构体中,`@Require`只能与`@Param`一起使用; + * 4. 检查自定义组件中的`@Local`属性和无装饰器属性是否尝试在外部初始化; + * 5. 确保`@Local`,`@Param`,`@Event`装饰器只能用于成员属性,而不能用于方法。 + * + * 校验等级:error + */ +export function checkComponentV2StateUsage(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +function checkComponentV2StateUsageInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.annotationInfo?.hasComponentV2) { + return; + } + const decorators = findStructAttributeBuiltInDecoratorsFromInfo(metadata); + // 成员属性不能同时被多个内置装饰器(`@Local`, `@Param`, `@Event`)装饰 + if (decorators.length > 1) { + decorators.forEach((info) => + this.report({ + node: info.annotation, + message: `The member property or method cannot be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + }) + ); + } + // 当用`@Param`装饰的变量没有被分配默认值时,它也必须用`@Require`装饰 + if (checkIsParamNotPairedWithRequireFromInfo(metadata)) { + const position = node.startPosition; + this.report({ + node, + message: `When a variable decorated with '@Param' is not assigned a default value, it must also be decorated with '@Require'.`, + level: LogType.ERROR, + suggestion: createSuggestion(`@${DecoratorNames.REQUIRE}`, position, position), + }); + } + // 在被`@ComponentV2`装饰的结构体中,`@Require`只能与`@Param`一起使用 + if (checkIsRequireNotPariedWithParamOrBuilderParam(metadata)) { + const requiredDecorator = metadata.annotations?.[DecoratorNames.REQUIRE]!; + this.report({ + node: requiredDecorator, + message: `In a struct decorated with '@ComponentV2', '@Require' can only be used with '@Param' or '@BuilderParam'.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(requiredDecorator)), + }); + } +} + +function checkComponentV2StateUsageInStructCall( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structDeclInfo?.name) { + return; + } + const structName = metadata.structDeclInfo.name; + const call = coerceToAstNode(node); + const optionsArg = call.arguments.at(1); // Options is the second argument of a custom component call. + if (!optionsArg || !arkts.isObjectExpression(optionsArg)) { + return; + } + // 检查自定义组件中的`@Local`属性和无装饰器属性是否尝试在外部初始化 + (optionsArg.properties as arkts.Property[]).forEach((prop) => { + let decl: arkts.AstNode | undefined; + if (!prop.key || !prop.value || !(decl = arkts.getPeerPropertyDecl(prop.peer)) || !arkts.isMethodDefinition(decl)) { + return; + } + if (checkIsNameStartWithBackingField(decl.name)) { + return; + } + const structInterfacePropRecord = RecordBuilder.build(CustomComponentInterfacePropertyRecord, decl, { + shouldIgnoreDecl: true, + }); // TODO: change back to false; + if (!structInterfacePropRecord.isCollected) { + structInterfacePropRecord.collect(decl); + } + const propertyInfo = structInterfacePropRecord.toRecord(); + let reportDecoratorName: string | undefined; + if (propertyInfo?.annotationInfo?.hasLocal) { + reportDecoratorName = `@${DecoratorNames.LOCAL}`; + } else if (!propertyInfo?.annotationInfo || Object.keys(propertyInfo.annotationInfo).length === 0) { + reportDecoratorName = 'regular'; + } + if (!!reportDecoratorName) { + this.report({ + node: prop, + message: getLocalNeedNoInitReportMessage(reportDecoratorName, decl.name.name, structName), + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(prop)), + }); + } + }); +} + +function checkComponentV2StateUsageInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.annotationInfo?.hasComponentV2) { + return; + } + const decorators = findStructAttributeBuiltInDecoratorsFromInfo(metadata); + // 确保`@Local`,`@Param`,`@Event`装饰器只能用于成员属性,而不能用于方法 + if (decorators.length > 0) { + decorators.forEach((info) => + this.report({ + node: info.annotation, + message: `'@${info.name}' can only decorate member property.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(info.annotation)), + }) + ); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkComponentV2StateUsageInClassProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, checkComponentV2StateUsageInStructCall], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkComponentV2StateUsageInStructMethod], +]); + +interface DecoratorInfo { + name: string; + annotation: arkts.AnnotationUsage; +} + +const builtInDecorators: string[] = [DecoratorNames.LOCAL, DecoratorNames.PARAM, DecoratorNames.EVENT]; + +function getLocalNeedNoInitReportMessage(decorator: string, key: string, component: string): string { + return `The '${decorator}' property '${key}' in the custom component '${component}' cannot be initialized here (forbidden to specify).`; +} + +function findStructAttributeBuiltInDecoratorsFromInfo(info: StructPropertyInfo | StructMethodInfo): DecoratorInfo[] { + if (!info.annotationInfo || !info.annotations) { + return []; + } + return builtInDecorators + .filter((name) => !!info.annotationInfo?.[`has${name}`]) + .map((name) => ({ + name, + annotation: info.annotations?.[name]!, + })); +} + +function checkIsParamNotPairedWithRequireFromInfo(info: StructPropertyInfo): boolean { + if (!info.annotationInfo) { + return false; + } + return !!info.annotationInfo.hasParam && !info.annotationInfo.hasRequire; +} + +function checkIsRequireNotPariedWithParamOrBuilderParam(info: StructPropertyInfo): boolean { + if (!info.annotationInfo || !info.annotationInfo.hasRequire) { + return false; + } + return !info.annotationInfo.hasParam && !info.annotationInfo.hasBuilderParam; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts new file mode 100644 index 000000000..1ed491001 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts @@ -0,0 +1,246 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { coerceToAstNode } from '../utils'; +import type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { + CallInfo, + NormalClassMethodAnnotationRecord, + NormalClassMethodInfo, + NormalClassPropertyInfo, + RecordBuilder, + StructMethodInfo, + StructMethodRecord, + StructPropertyInfo, +} from '../../records'; +import { DecoratorNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; + +/** + * 校验规则: + * 1. `@Computed`装饰器只能用来装饰获取器(即`getter`方法); + * 2. `@Computed`装饰器在已经被`@ObservedV2`装饰器装饰的类`class`中的成员方法上使用; + * 3. `@Computed`装饰器在已经被`@ComponentV2`装饰器修饰的结构体`struct`中使用 + * 4. `@Computed`装饰器修饰的属性不能与双向绑定语法一起使用; + * 5. `@Computed`装饰器修饰的属性不能定义一个设置器(即`setter`方法)。 + * + * 校验等级:error + */ +export function checkComputedDecorator( + this: BaseValidator, + node: arkts.AstNode, + other?: arkts.AstNode +): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node, other); + } +} + +function checkComputedDecoratorInMethod< + T extends arkts.AstNode = arkts.MethodDefinition, + U extends arkts.AstNode = arkts.ClassDefinition +>(this: BaseValidator, node: T, classDecl?: U): void { + const metadata = this.context ?? {}; + const method = coerceToAstNode(node); + const classDef = classDecl ? coerceToAstNode(classDecl) : undefined; + const setter = findSetterMethod(method, metadata); + const getter = findGetterFromSetterMethod(setter, classDef); + if (!!setter && !!getter && checkIsMethodHasComputed(getter)) { + // `@Computed`装饰器修饰的属性不能定义一个设置器(即`setter`方法) + this.report({ + node: setter, + message: `A property decorated by '@Computed' cannot define a set method.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(setter)), + }); + } + if (!metadata.annotationInfo?.hasComputed) { + return; + } + const computedAnnotation = metadata.annotations?.[DecoratorNames.COMPUTED]!; + if (!checkIsGetterMethod(method, metadata)) { + // `@Computed`装饰器只能用来装饰获取器(即`getter`方法) + this.report({ + node: computedAnnotation, + message: `@${DecoratorNames.COMPUTED} can only decorate 'GetAccessor'.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(computedAnnotation)), + }); + } else if (!checkIsFromObervedV2InNormalClass(metadata) && !!classDef?.parent) { + // `@Computed`装饰器在已经被`@ObservedV2`装饰器装饰的类`class`中的成员方法上使用 + this.report({ + node: computedAnnotation, + message: `The '@Computed' can decorate only member method within a 'class' decorated with ObservedV2.`, + level: LogType.ERROR, + suggestion: createSuggestion( + `@${DecoratorNames.OBSERVED_V2}`, + ...getPositionRangeFromNode(classDef.parent) + ), + }); + } else if (!checkIsFromComponentV2InStruct(metadata) && !!classDef?.parent) { + // `@Computed`装饰器在已经被`@ComponentV2`装饰器修饰的结构体`struct`中使用 + this.report({ + node: computedAnnotation, + message: `The '@Computed' annotation can only be used in a 'struct' decorated with ComponentV2.`, + level: LogType.ERROR, + suggestion: createSuggestion( + `@${StructDecoratorNames.COMPONENT_V2}`, + ...getPositionRangeFromNode(classDef.parent) + ), + }); + } +} + +function checkComputedDecoratorInProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Since property cannot have `@Computed`, it is an ignored annotation. + if (!metadata.ignoredAnnotationInfo?.hasComputed) { + return; + } + const computedAnnotation = metadata.ignoredAnnotations?.[DecoratorNames.COMPUTED]!; + // `@Computed`装饰器只能用来装饰获取器(即`getter`方法) + this.report({ + node: computedAnnotation, + message: `@${DecoratorNames.COMPUTED} can only decorate 'GetAccessor'.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(computedAnnotation)), + }); +} + +function checkComputedDecoratorInStructCall( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structDeclInfo?.name) { + return; + } + const call = coerceToAstNode(node); + const optionsArg = call.arguments.at(1); // Options is the second argument of a custom component call. + if (!optionsArg || !arkts.isObjectExpression(optionsArg)) { + return; + } + // `@Computed`装饰器修饰的属性不能与双向绑定语法一起使用 + (optionsArg.properties as arkts.Property[]).forEach((prop) => { + if (!prop.key || !prop.value || !arkts.isCallExpression(prop.value)) { + return; + } + const computedArgs = findComputedArgInBindablePropertyValue(prop.value.arguments); + computedArgs.forEach((node) => { + this.report({ + node, + message: `A property decorated by '@Computed' cannot be used with two-way bind syntax.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(node)), + }); + }); + }); +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkComputedDecoratorInMethod], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkComputedDecoratorInProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, checkComputedDecoratorInStructCall], +]); + +type MethodInfo = StructMethodInfo & NormalClassMethodInfo; + +type PropertyInfo = StructPropertyInfo & NormalClassPropertyInfo; + +function findComputedArgInBindablePropertyValue(args: readonly arkts.Expression[]): readonly arkts.Expression[] { + return args.filter((arg) => { + if (!arkts.isMemberExpression(arg) || !arkts.isThisExpression(arg.object)) { + return false; + } + const decl = arkts.getPeerIdentifierDecl(arg.property.peer); + if (!decl || !arkts.isMethodDefinition(decl)) { + return false; + } + const structMethodRecord = RecordBuilder.build(StructMethodRecord, decl, { shouldIgnoreDecl: true }); // TODO: change back to false; + if (!structMethodRecord.isCollected) { + structMethodRecord.collect(decl); + } + const methodInfo = structMethodRecord.toRecord(); + return !!methodInfo?.annotationInfo?.hasComputed; + }); +} + +function checkIsFromComponentV2InStruct(info: MethodInfo | PropertyInfo): boolean { + if (!info.structInfo && !!info.classInfo) { + return true; // Skip checking. This implies from normal class rather than from struct. + } + return !!info.structInfo?.annotationInfo?.hasComponentV2; +} + +function checkIsFromObervedV2InNormalClass(info: MethodInfo | PropertyInfo): boolean { + if (!info.classInfo && !!info.structInfo) { + return true; // Skip checking. This implies from struct rather than from normal class. + } + return !!info.classInfo?.annotationInfo?.hasObservedV2; +} + +function checkIsGetterMethod(node: arkts.MethodDefinition, info?: MethodInfo): boolean { + if (info?.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + return true; + } + let isGetter: boolean = node.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET; + if (!isGetter) { + isGetter = node.overloads.some((method) => checkIsGetterMethod(method)); + } + return isGetter; +} + +function findSetterMethod(node: arkts.MethodDefinition, info?: MethodInfo): arkts.MethodDefinition | undefined { + if (info?.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + return node; + } + let isSetter: boolean = node.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET; + if (isSetter) { + return node; + } + return node.overloads.find((method) => findSetterMethod(method)); +} + +function findGetterFromSetterMethod( + setter: arkts.MethodDefinition | undefined, + classDecl: arkts.ClassDefinition | undefined +): arkts.MethodDefinition | undefined { + if (!setter || !classDecl) { + return undefined; + } + const getterInOverload = setter.overloads.find((method) => checkIsGetterMethod(method)); + if (!!getterInOverload) { + return getterInOverload; + } + const name = setter.name.name; + return classDecl.body.find( + (st) => arkts.isMethodDefinition(st) && checkIsGetterMethod(st) && st.name.name === name + ) as arkts.MethodDefinition | undefined; +} + +function checkIsMethodHasComputed(node: arkts.MethodDefinition): boolean { + const annotationRecord = new NormalClassMethodAnnotationRecord({ shouldIgnoreDecl: true }); // TODO: change back to false; + for (const annotation of node.scriptFunction.annotations) { + annotationRecord.collect(annotation); + } + const annotationInfo = annotationRecord.toRecord(); + return !!annotationInfo?.annotationInfo?.hasComputed; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts new file mode 100644 index 000000000..17018daf9 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts @@ -0,0 +1,207 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { coerceToAstNode } from '../utils'; +import type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { + CallInfo, + CustomComponentInterfacePropertyRecord, + NormalClassPropertyInfo, + RecordBuilder, + StructMethodInfo, + StructPropertyInfo, +} from '../../records'; +import { checkIsNameStartWithBackingField } from '../../utils'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; + +/** + * 校验规则: + * 1. `@Provider`/`@Consumer`只能用来修饰类成员属性(不能修饰方法、参数等); + * 2. 结构体成员变量不能被多个内置装饰器修饰; + * 3. `@Provider`/`@Consumer`装饰器只能用于`struct`类型,而不能用于类(`class`)或其他类型; + * 4. 自定义组件中的`@Provider`/`@Consumer`装饰的属性不能在父组件初始化(禁止指定初始值)。 + * + * 校验等级:error + */ +export function checkConsumerProviderDecorator( + this: BaseValidator, + node: arkts.AstNode, + other?: arkts.AstNode +): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node, other); + } +} + +function checkConsumerProviderDecoratorInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Provider`/`@Consumer`只能用来修饰类成员属性(不能修饰方法、参数等); + if (metadata.ignoredAnnotationInfo?.hasConsumer) { + const annotation = metadata.ignoredAnnotations?.[DecoratorNames.CONSUMER]!; + this.report({ + node: annotation, + message: `'@${DecoratorNames.CONSUMER}' can only decorate member property.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(annotation)), + }); + } + if (metadata.ignoredAnnotationInfo?.hasProvider) { + const annotation = metadata.ignoredAnnotations?.[DecoratorNames.PROVIDER]!; + this.report({ + node: annotation, + message: `'@${DecoratorNames.PROVIDER}' can only decorate member property.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(annotation)), + }); + } +} + +function checkConsumerProviderDecoratorInProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + //`@Provider`/`@Consumer`装饰器只能用于`struct`类型,而不能用于类(`class`)或其他类型; + if (!!metadata.classInfo && metadata.ignoredAnnotationInfo?.hasConsumer) { + const annotation = metadata.ignoredAnnotations?.[DecoratorNames.CONSUMER]!; + this.report({ + node: annotation, + message: `The '@${DecoratorNames.CONSUMER}' annotation can only be used with 'struct'.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(annotation)), + }); + } + if (!!metadata.classInfo && metadata.ignoredAnnotationInfo?.hasProvider) { + const annotation = metadata.ignoredAnnotations?.[DecoratorNames.PROVIDER]!; + this.report({ + node: annotation, + message: `The '@${DecoratorNames.PROVIDER}' annotation can only be used with 'struct'.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(annotation)), + }); + } + // 结构体成员变量不能被多个内置装饰器修饰; + let foundOther: arkts.AnnotationUsage | undefined; + if ( + metadata.annotationInfo?.hasConsumer && + !!(foundOther = findOtherDecoratorFromInfo(metadata, DecoratorNames.CONSUMER)) + ) { + this.report({ + node: foundOther, + message: `The struct member variable can not be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(foundOther)), + }); + } + if ( + metadata.annotationInfo?.hasProvider && + !!(foundOther = findOtherDecoratorFromInfo(metadata, DecoratorNames.PROVIDER)) + ) { + this.report({ + node: foundOther, + message: `The struct member variable can not be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(foundOther)), + }); + } +} + +function checkConsumerProviderDecoratorInStructCall( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structDeclInfo?.name) { + return; + } + const structName = metadata.structDeclInfo.name; + const call = coerceToAstNode(node); + const optionsArg = call.arguments.at(1); // Options is the second argument of a custom component call. + if (!optionsArg || !arkts.isObjectExpression(optionsArg)) { + return; + } + // 自定义组件中的`@Provider`/`@Consumer`装饰的属性不能在父组件初始化(禁止指定初始值) + (optionsArg.properties as arkts.Property[]).forEach((prop) => { + let decl: arkts.AstNode | undefined; + if (!prop.key || !prop.value || !(decl = arkts.getPeerPropertyDecl(prop.peer)) || !arkts.isMethodDefinition(decl)) { + return; + } + if (checkIsNameStartWithBackingField(decl.name)) { + return; + } + const decoratorInfo = findConsumerOrProviderFromInterfaceProperty(decl); + if (!!decoratorInfo) { + this.report({ + node: prop, + message: getForbiddenInitializationMessage(decoratorInfo.name, decl.name.name, structName), + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(call)), + }); + } + }); +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkConsumerProviderDecoratorInStructMethod], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkConsumerProviderDecoratorInProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, checkConsumerProviderDecoratorInStructCall], +]); + +type PropertyInfo = StructPropertyInfo & NormalClassPropertyInfo; + +interface DecoratorInfo { + name: string; + annotation: arkts.AnnotationUsage; +} + +function findOtherDecoratorFromInfo(info: StructPropertyInfo, except: string): arkts.AnnotationUsage | undefined { + let foundName: string | undefined; + foundName = Object.keys(info.annotations ?? {}).find((name) => name !== except); + if (!!foundName) { + return info.annotations?.[foundName]!; + } + foundName = Object.keys(info.ignoredAnnotations ?? {}).find((name) => name !== except); + return foundName ? info.ignoredAnnotations?.[foundName] : undefined; +} + +function findConsumerOrProviderFromInterfaceProperty(property: arkts.MethodDefinition): DecoratorInfo | undefined { + const structInterfacePropRecord = RecordBuilder.build(CustomComponentInterfacePropertyRecord, property, { + shouldIgnoreDecl: true, + }); // TODO: change back to false; + if (!structInterfacePropRecord.isCollected) { + structInterfacePropRecord.collect(property); + } + const propertyInfo = structInterfacePropRecord.toRecord(); + if (propertyInfo?.annotationInfo?.hasConsumer) { + const annotation = propertyInfo.annotations?.[DecoratorNames.CONSUMER]!; + return { name: DecoratorNames.CONSUMER, annotation }; + } + if (propertyInfo?.annotationInfo?.hasProvider) { + const annotation = propertyInfo.annotations?.[DecoratorNames.PROVIDER]!; + return { name: DecoratorNames.PROVIDER, annotation }; + } + return undefined; +} + +function getForbiddenInitializationMessage(decorator: string, key: string, component: string): string { + return `The '@${decorator}' property '${key}' in the custom component '${component}' cannot be initialized here (forbidden to specify).`; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts new file mode 100644 index 000000000..d8fa65ded --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts @@ -0,0 +1,57 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { StructPropertyInfo } from '../../records'; +import { EntryParamNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; + +/** + * 校验规则:`struct`结构体中使用了`@LocalStorageLink`来绑定属性,需要在`@Entry`装饰器中传入storage参数 + * + * 校验等级:warn + */ +export function checkEntryLocalStorage( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.annotationInfo?.hasLocalStorageLink || !metadata.structInfo?.annotationInfo?.hasEntry) { + return; + } + const entryAnnotation = metadata.structInfo?.annotations?.[StructDecoratorNames.ENTRY]!; + if (!findStorageParamFromEntryAnnotation(entryAnnotation)) { + this.report({ + node: entryAnnotation, + level: LogType.WARN, + message: `'@Entry' should have a parameter, like '@Entry ({ storage: "__get_local_storage__" })'.`, + }); + } +} + +function findStorageParamFromEntryAnnotation(node: arkts.AnnotationUsage): boolean { + return !!node.properties.find((prop) => { + if (!arkts.isClassProperty(prop)) { + return false; + } + if (!prop.key || !arkts.isIdentifier(prop.key) || prop.key.name !== EntryParamNames.ENTRY_STORAGE) { + return false; + } + if (!prop.value || !arkts.isStringLiteral(prop.value) || prop.value.str.length === 0) { + return false; + } + return true; + }); +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts new file mode 100644 index 000000000..3a547be7d --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts @@ -0,0 +1,55 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from '../base'; +import { isAnnotatedProperty } from '../utils'; +import { CallInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; + +/** + * 校验规则: + * 1. 原子组件不可包含子组件; + * 2. 单子组件最多允许包含一个组件; + * 3. 特定组件的父组件必须是限定组件; + * 4. 特定组件的子组件必须是限定组件。 + * + * 校验等级:error + */ +export function checkNestedRelationship( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + const fromComponentV2: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasComponentV2; + const isComponentCall: boolean = !!metadata.structDeclInfo?.annotationInfo?.hasComponent; + if (!(fromComponentV2 && isComponentCall)) { + return; + } + + // 只要当前struct 中有被"@Link" 修饰的属性就报错 + for (const member of struct.body) { + if (isAnnotatedProperty(member, DecoratorNames.LINK)) { + const declaration = struct.parent!; // Class Declaration has correct position information + this.report({ + node: declaration, + level: LogType.ERROR, + message: `A V2 component cannot be used with any member property annotated by '@Link' in a V1 component.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(declaration)), + }); + } + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts b/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts new file mode 100644 index 000000000..145dcadc5 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export * from './check-builder-param'; +export * from './check-component-link-init'; +export * from './check-component-v2-mix-use'; +export * from './check-componentV2-state-usage'; +export * from './check-computed-decorator'; +export * from './check-consumer-provider-decorator'; +export * from './check-entry-localstorage'; \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/validators/safe-types.ts b/arkui-plugins/collectors/ui-collectors/validators/safe-types.ts new file mode 100644 index 000000000..2d69f1717 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/safe-types.ts @@ -0,0 +1,30 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; + +export type IntrinsicValidatorFunction = (this: BaseValidator, node: T) => void; + +export type ModifiedValidatorFunction = ( + this: BaseValidator, + node: U +) => void; + +export type ExtendedValidatorFunction = ( + this: BaseValidator, + node: T, + other?: U +) => void; \ No newline at end of file diff --git a/arkui-plugins/collectors/ui-collectors/validators/struct-call-validator.ts b/arkui-plugins/collectors/ui-collectors/validators/struct-call-validator.ts new file mode 100644 index 000000000..aeecdfbef --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/struct-call-validator.ts @@ -0,0 +1,38 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { checkBuilderParam, checkComponentLinkInit, checkComponentV2StateUsage, checkComputedDecorator, checkConsumerProviderDecorator } from './rules'; +import { CallInfo } from '../records'; +import { checkIsCustomComponentFromInfo } from '../utils'; + +export class StructCallValidator extends BaseValidator { + reportIfViolated(node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // 只处理自定义组件 CallExpression的场景 + if (!checkIsCustomComponentFromInfo(metadata.structDeclInfo) || !metadata.structDeclInfo?.definitionPtr) { + return; + } + + checkComponentV2StateUsage.bind(this)(node); + checkComputedDecorator.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); + + const struct = arkts.classByPeer(metadata.structDeclInfo.definitionPtr); + checkBuilderParam.bind(this)(struct); + checkComponentLinkInit.bind(this)(struct); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts b/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts new file mode 100644 index 000000000..d360d7ff5 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts @@ -0,0 +1,34 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { StructMethodInfo } from '../records'; +import { checkComponentV2StateUsage, checkComputedDecorator, checkConsumerProviderDecorator } from './rules'; + +export class StructMethodValidator extends BaseValidator { + reportIfViolated(node: arkts.MethodDefinition): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.definitionPtr) { + return; + } + + checkComponentV2StateUsage.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); + + const struct = arkts.classByPeer(metadata.structInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, struct); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts b/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts new file mode 100644 index 000000000..d90833850 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts @@ -0,0 +1,42 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { StructPropertyInfo } from '../records'; +import { + checkComponentV2MixUse, + checkComponentV2StateUsage, + checkComputedDecorator, + checkConsumerProviderDecorator, + checkEntryLocalStorage, +} from './rules'; + +export class StructPropertyValidator extends BaseValidator { + reportIfViolated(node: arkts.ClassProperty): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.definitionPtr) { + return; + } + + checkComponentV2MixUse.bind(this)(node); + checkComponentV2StateUsage.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); + checkEntryLocalStorage.bind(this)(node); + + const struct = arkts.classByPeer(metadata.structInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, struct); + } +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/utils.ts b/arkui-plugins/collectors/ui-collectors/validators/utils.ts new file mode 100644 index 000000000..2a3cf8c22 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/utils.ts @@ -0,0 +1,38 @@ +/* + * 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 arkts from '@koalaui/libarkts'; +import { getAnnotationName } from '../utils'; + +export function isAnnotatedProperty(node: arkts.AstNode, annotationName: string, ignoreDecl: boolean = false): node is arkts.ClassProperty { + if (!arkts.isClassProperty(node)) { + return false; + } + return !!getAnnotationByName(node.annotations, annotationName, ignoreDecl); +} + +export function getAnnotationByName( + annotations: readonly arkts.AnnotationUsage[], + name: string, + ignoreDecl: boolean = false +): arkts.AnnotationUsage | undefined { + return annotations.find((annotation: arkts.AnnotationUsage): boolean => { + return getAnnotationName(annotation, ignoreDecl) === name; + }); +} + +export function coerceToAstNode(node: arkts.AstNode): T { + return node as T; +} diff --git a/arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts b/arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts new file mode 100644 index 000000000..1fd84c369 --- /dev/null +++ b/arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts @@ -0,0 +1,27 @@ +/* + * 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 { Validator } from './base'; +import { clearValidatorCache, getOrPut } from './cache'; + +export class ValidatorBuilder { + static build(Validator: { name: string; new (): Validator }): Validator { + return getOrPut(Validator.name, () => new Validator()); + } + + static reset(): void { + clearValidatorCache(); + } +} diff --git a/arkui-plugins/common/arkts-utils.ts b/arkui-plugins/common/arkts-utils.ts index 59016f2fd..76fcc2b08 100644 --- a/arkui-plugins/common/arkts-utils.ts +++ b/arkui-plugins/common/arkts-utils.ts @@ -66,7 +66,7 @@ export function isDecoratorAnnotation( if (!decl) { return false; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName)) { return false; } @@ -82,24 +82,6 @@ export function removeAnnotationByName( return annotations.filter((it) => !isAnnotation(it, annoName)); } -export function expectName(node: arkts.AstNode | undefined): string { - if (!node) { - throw new Error('Expected an identifier, got empty node'); - } - if (!arkts.isIdentifier(node)) { - throw new Error('Expected an identifier, got: ' + arkts.nodeType(node).toString()); - } - return node.name; -} - -export function mangle(value: string): string { - return `__${value}`; -} - -export function backingField(originalName: string): string { - return mangle(`backing_${originalName}`); -} - export function filterDefined(value: (T | undefined)[]): T[] { return value.filter((it: T | undefined): it is T => it != undefined); } diff --git a/arkui-plugins/common/declaration-collector.ts b/arkui-plugins/common/declaration-collector.ts index d65f0d40d..a867d3d18 100644 --- a/arkui-plugins/common/declaration-collector.ts +++ b/arkui-plugins/common/declaration-collector.ts @@ -62,7 +62,10 @@ export class DeclarationCollector { if (!declName) { return; } - let sourceName: string = arkts.getProgramFromAstNode(decl).moduleName; + let sourceName = arkts.getProgramFromAstNode(decl)?.moduleName; + if (!sourceName) { + return; + } this.fromExternalSourceNameMap.set(declName, sourceName); this.fromExternalSourceNodePeerMap.set(decl.peer, sourceName); diff --git a/arkui-plugins/common/log-collector.ts b/arkui-plugins/common/log-collector.ts index 5fa9ed7af..775265282 100644 --- a/arkui-plugins/common/log-collector.ts +++ b/arkui-plugins/common/log-collector.ts @@ -16,20 +16,59 @@ import * as arkts from '@koalaui/libarkts'; import { LogType } from './predefines'; -interface LogInfo { - type: LogType; - message: string; - node: arkts.AstNode; +export interface SuggestionOptions { code: string; + range: [start: arkts.SourcePosition, end: arkts.SourcePosition]; + args?: string[]; +} + +export interface LogInfo { + node: arkts.AstNode; + level: LogType; + message: string; + args?: string[]; + position?: arkts.SourcePosition; + suggestion?: SuggestionOptions; + code?: string; +} + +export function createSuggestion( + code: string, + rangeStart: arkts.SourcePosition, + rangeEnd: arkts.SourcePosition, + ...args: string[] +): SuggestionOptions { + return { code, range: [rangeStart, rangeEnd], args }; +} + +export function getPositionRangeFromNode(node: arkts.AstNode): [arkts.SourcePosition, arkts.SourcePosition] { + return [node.startPosition, node.endPosition]; } export function generateDiagnosticKind(logItem: LogInfo): arkts.DiagnosticKind { - return arkts.DiagnosticKind.create( - `${logItem.code}: ${logItem.message}`, - logItem.type === LogType.ERROR + const message: string = !!logItem.code ? `${logItem.code}: ${logItem.message}` : logItem.message; + const level: arkts.PluginDiagnosticType = + logItem.level === LogType.ERROR ? arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_ERROR - : arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_WARNING - ); + : arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_WARNING; + return arkts.DiagnosticKind.create(message, level); +} + +export function generateDiagnosticInfo(logItem: LogInfo): arkts.DiagnosticInfo { + const diagnosticArgs = logItem.args ?? []; + const diagnosticKind = generateDiagnosticKind(logItem); + return arkts.DiagnosticInfo.create(diagnosticKind, ...diagnosticArgs); +} + +export function generateSuggestionInfo(suggestion: SuggestionOptions, message: string): arkts.SuggestionInfo { + const suggestionArgs = suggestion.args ?? []; + const suggestionKind = arkts.DiagnosticKind.create(message, arkts.PluginDiagnosticType.ES2PANDA_PLUGIN_SUGGESTION); + return arkts.SuggestionInfo.create(suggestionKind, suggestion.code, ...suggestionArgs); +} + +export function generateSuggestionRange(suggestion: SuggestionOptions): arkts.SourceRange { + const [startPosition, endPosition] = suggestion.range; + return arkts.SourceRange.create(startPosition, endPosition); } export class LogCollector { @@ -49,6 +88,21 @@ export class LogCollector { return this.instance; } + private reportDiagnostic(log: LogInfo): void { + const args = log.args ?? []; + const position = log.position ?? arkts.getStartPosition(log.node); + const suggestion = log.suggestion; + if (!suggestion) { + const kind = generateDiagnosticKind(log); + arkts.Diagnostic.logDiagnostic(kind, position, ...args); + } else { + const info = generateDiagnosticInfo(log); + const suggestionInfo = generateSuggestionInfo(suggestion, log.message); + const suggestionRange = generateSuggestionRange(suggestion); + arkts.Diagnostic.logDiagnosticWithSuggestion(info, suggestionInfo, suggestionRange); + } + } + reset(): void { this.logInfos = []; this.ignoreError = false; @@ -63,7 +117,7 @@ export class LogCollector { return; } this.logInfos.forEach((logItem: LogInfo) => { - arkts.Diagnostic.logDiagnostic(generateDiagnosticKind(logItem), arkts.getStartPosition(logItem.node)); + this.reportDiagnostic(logItem); }); } diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index bfe8a0313..735603c2c 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -27,11 +27,7 @@ export const EXTERNAL_SOURCE_PREFIX_NAMES: (string | RegExp)[] = [ /ability\..*/, ]; -export const EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK: (string | RegExp)[] = [ - 'std', - 'escompat', - /@arkts\..*/ -]; +export const EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK: (string | RegExp)[] = ['std', 'escompat', /@arkts\..*/]; export const ARKUI_IMPORT_PREFIX_NAMES: (string | RegExp)[] = [/arkui\..*/, /@ohos\..*/, /@kit\..*/]; @@ -92,13 +88,13 @@ export enum EntryWrapperNames { REGISTER_NAMED_ROUTER = 'RegisterNamedRouter', ROUTER_NAME = 'routerName', INSTANCE = 'instance', - PARAM = 'param' + PARAM = 'param', } export enum EntryParamNames { ENTRY_STORAGE = 'storage', ENTRY_USE_SHARED_STORAGE = 'useSharedStorage', - ENTRY_ROUTE_NAME = 'routeName' + ENTRY_ROUTE_NAME = 'routeName', } export enum InnerComponentNames { @@ -115,6 +111,7 @@ export enum DecoratorNames { CONSUME = 'Consume', OBJECT_LINK = 'ObjectLink', OBSERVED = 'Observed', + OBSERVED_V2 = 'ObservedV2', WATCH = 'Watch', BUILDER_PARAM = 'BuilderParam', BUILDER = 'Builder', @@ -127,13 +124,15 @@ export enum DecoratorNames { JSONRENAME = 'JSONRename', ANIMATABLE_EXTEND = 'AnimatableExtend', PROP_REF = 'PropRef', - LOCAL = 'Local', - LOCAL_STORAGE_PROP_REF = 'LocalStoragePropRef', + LOCAL_STORAGE_PROP_REF = 'LocalStoragePropRef', STORAGE_PROP_REF = 'StoragePropRef', -} - -export enum DecoratorIntrinsicNames { - LINK = '__Link_intrinsic', + LOCAL = 'Local', + PARAM = 'Param', + EVENT = 'Event', + REQUIRE = 'Require', + COMPUTED = 'Computed', + CONSUMER = 'Consumer', + PROVIDER = 'Provider', } export enum StateManagementTypes { @@ -158,6 +157,7 @@ export enum StateManagementTypes { RENDER_ID_TYPE = 'RenderIdType', OBSERVE = 'OBSERVE', META = '__meta', + BACKING = '__backing', SUBSCRIBED_WATCHES = 'ISubscribedWatches', STORAGE_LINK_STATE = 'StorageLinkState', OBSERVABLE_PROXY = 'observableProxy', @@ -201,6 +201,43 @@ export enum ConditionNames { CONDITION_BRANCH = 'ConditionBranch', } +export enum CustomComponentNames { + COMPONENT_BUILD_ORI = 'build', + COMPONENT_CONSTRUCTOR_ORI = 'constructor', + COMPONENT_CLASS_NAME = 'CustomComponent', + COMPONENT_V2_CLASS_NAME = 'CustomComponentV2', + BASE_CUSTOM_DIALOG_NAME = 'BaseCustomDialog', + COMPONENT_INTERFACE_PREFIX = '__Options_', + COMPONENT_INITIALIZE_STRUCT = '__initializeStruct', + COMPONENT_UPDATE_STRUCT = '__updateStruct', + COMPONENT_INITIALIZERS_NAME = 'initializers', + BUILD_COMPATIBLE_NODE = '_buildCompatibleNode', + OPTIONS = 'options', + PAGE_LIFE_CYCLE = 'PageLifeCycle', + LAYOUT_CALLBACK = 'LayoutCallback', +} + +export enum CustomDialogNames { + CUSTOM_DIALOG_ANNOTATION_NAME = 'CustomDialog', + CUSTOM_DIALOG_CONTROLLER = 'CustomDialogController', + CUSTOM_DIALOG_CONTROLLER_OPTIONS = 'CustomDialogControllerOptions', + SET_DIALOG_CONTROLLER_METHOD = '__setDialogController__', + CONTROLLER = 'controller', + OPTIONS_BUILDER = 'builder', + BASE_COMPONENT = 'baseComponent', + EXTENDABLE_COMPONENT = 'ExtendableComponent', + CUSTOM_BUILDER = 'CustomBuilder', +} + +export enum BuilderLambdaNames { + ANNOTATION_NAME = 'ComponentBuilder', + ORIGIN_METHOD_NAME = '$_instantiate', + TRANSFORM_METHOD_NAME = '_instantiateImpl', + STYLE_PARAM_NAME = 'style', + STYLE_ARROW_PARAM_NAME = 'instance', + CONTENT_PARAM_NAME = 'content' +} + export const RESOURCE_TYPE: Record = { color: 10001, float: 10002, @@ -238,7 +275,14 @@ export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map = new Map = new Map = new Map [StateManagementTypes.STORAGE_LINK_STATE, 'arkui.stateManagement.runtime'], [StateManagementTypes.OBSERVABLE_PROXY, 'arkui.stateManagement.runtime'], [StateManagementTypes.PROP_STATE, 'arkui.stateManagement.runtime'], - [AnimationNames.ANIMATABLE_ARITHMETIC, 'arkui.component.common'] + [AnimationNames.ANIMATABLE_ARITHMETIC, 'arkui.component.common'], ]); export enum GetSetTypes { @@ -304,7 +348,20 @@ export enum GetSetTypes { SET = 'set', } -export enum GenSymPrefix { - INTRINSIC = 'gensym%%', - UI = 'gensym__' +export enum NodeCacheNames { + MEMO = 'memo', + UI = 'ui', +} + +export enum BuiltInNames { + GENSYM_INTRINSIC_PREFIX = 'gensym%%', + GENSYM_UI_PREFIX = 'gensym__', + ETS_GLOBAL_CLASS = 'ETSGLOBAL', + GLOBAL_INIT_METHOD = '_$init$_', + GLOBAL_MAIN_METHOD = 'main', + IMPLEMENT_PROPETY_PREFIX = '' +} + +export enum ArkUIDeclInterfaceNames { + COMMON_METHOD = 'CommonMethod' } \ No newline at end of file diff --git a/arkui-plugins/common/safe-types.ts b/arkui-plugins/common/safe-types.ts index 899ef0c39..87345cf19 100644 --- a/arkui-plugins/common/safe-types.ts +++ b/arkui-plugins/common/safe-types.ts @@ -40,4 +40,6 @@ export type PickNested = { [P in keyof T]: P extends K ? T[P] : T[P] extends object ? NestedKey : T[P]; }; -export type PartialNestedExcept = PartialNested> & PickNested; \ No newline at end of file +export type PartialNestedExcept = PartialNested> & PickNested; + +export type AstNodePointer = arkts.AstNode['peer']; \ No newline at end of file diff --git a/arkui-plugins/memo-plugins/function-transformer.ts b/arkui-plugins/memo-plugins/function-transformer.ts index 4f2c55f1f..6caed7d5d 100644 --- a/arkui-plugins/memo-plugins/function-transformer.ts +++ b/arkui-plugins/memo-plugins/function-transformer.ts @@ -56,6 +56,7 @@ import { SignatureTransformer } from './signature-transformer'; import { moveToFront } from '../common/arkts-utils'; import { InternalsTransformer } from './internal-transformer'; import { CachedMetadata, rewriteByType } from './memo-cache-factory'; +import { NodeCacheNames } from '../common/predefines'; interface ScopeInfo extends MemoInfo { regardAsSameScope?: boolean; @@ -683,8 +684,8 @@ export class FunctionTransformer extends AbstractVisitor { private visitorWithCache(beforeChildren: arkts.AstNode): arkts.AstNode { const node = this.visitEachChild(beforeChildren); - if (arkts.NodeCache.getInstance().has(node)) { - const value = arkts.NodeCache.getInstance().get(node)!; + if (arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { + const value = arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(node)!; if (rewriteByType.has(value.type)) { this.modified = true; const metadata: CachedMetadata = { ...value.metadata, internalsTransformer: this.internalsTransformer }; diff --git a/arkui-plugins/memo-plugins/index.ts b/arkui-plugins/memo-plugins/index.ts index 5c19bc841..6f00963cf 100644 --- a/arkui-plugins/memo-plugins/index.ts +++ b/arkui-plugins/memo-plugins/index.ts @@ -20,7 +20,7 @@ import { PositionalIdTracker } from './utils'; import { ReturnTransformer } from './return-transformer'; import { ParameterTransformer } from './parameter-transformer'; import { ProgramVisitor } from '../common/program-visitor'; -import { EXTERNAL_SOURCE_PREFIX_NAMES, EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK } from '../common/predefines'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK, NodeCacheNames } from '../common/predefines'; import { debugDump, debugLog, getDumpFileName } from '../common/debug'; import { SignatureTransformer } from './signature-transformer'; import { InternalsTransformer } from './internal-transformer'; @@ -31,6 +31,7 @@ export function unmemoizeTransform(): Plugins { checked: checkedTransform, clean() { arkts.arktsGlobal.clearContext(); + arkts.NodeCacheFactory.getInstance().clear(); }, }; } @@ -49,7 +50,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { const canSkipPhases = !isFrameworkMode && program.canSkipPhases(); debugDump( script.dumpSrc(), - getDumpFileName(0, 'SRC', 5, 'MEMO_AfterCheck_Begin'), + getDumpFileName(0, 'SRC', 7, 'MEMO_AfterCheck_Begin'), true, cachePath, program.fileNameWithExtension @@ -61,7 +62,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { debugLog('[AFTER MEMO SCRIPT] script: ', script.dumpSrc()); debugDump( script.dumpSrc(), - getDumpFileName(0, 'SRC', 6, 'MEMO_AfterCheck_End'), + getDumpFileName(0, 'SRC', 8, 'MEMO_AfterCheck_End'), true, cachePath, program.fileNameWithExtension @@ -95,6 +96,7 @@ function checkedProgramVisit( debugLog('[SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); } else { debugLog('[CANT SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); + // arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).visualize(); const positionalIdTracker = new PositionalIdTracker(arkts.getFileName(), false); const parameterTransformer = new ParameterTransformer({ positionalIdTracker }); const returnTransformer = new ReturnTransformer(); @@ -109,7 +111,7 @@ function checkedProgramVisit( returnTransformer, signatureTransformer, internalsTransformer, - useCache: arkts.NodeCache.getInstance().isCollected(), + useCache: arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).isCollected(), }); const skipPrefixNames = isFrameworkMode ? EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK @@ -122,7 +124,7 @@ function checkedProgramVisit( pluginContext, }); program = programVisitor.programVisitor(program); - arkts.NodeCache.getInstance().clear(); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).clear(); } return program; } diff --git a/arkui-plugins/memo-plugins/memo-cache-factory.ts b/arkui-plugins/memo-plugins/memo-cache-factory.ts index e8151cb31..56e2d9469 100644 --- a/arkui-plugins/memo-plugins/memo-cache-factory.ts +++ b/arkui-plugins/memo-plugins/memo-cache-factory.ts @@ -28,9 +28,19 @@ import { PositionalIdTracker, } from './utils'; import { InternalsTransformer } from './internal-transformer'; -import { GenSymPrefix } from '../common/predefines'; +import { BuiltInNames } from '../common/predefines'; -export interface CachedMetadata extends arkts.AstNodeCacheValueMetadata { +export interface CacheValueMetadata { + callName?: string; + hasReceiver?: boolean; + isSetter?: boolean; + isGetter?: boolean; + hasMemoSkip?: boolean; + hasMemoIntrinsic?: boolean; + hasMemoEntry?: boolean; +} + +export interface CachedMetadata extends CacheValueMetadata { internalsTransformer?: InternalsTransformer; } @@ -108,7 +118,7 @@ export class RewriteFactory { static rewriteArrowFunction( node: arkts.ArrowFunctionExpression, - metadata?: arkts.AstNodeCacheValueMetadata, + metadata?: CachedMetadata, expectReturn?: arkts.TypeNode ): arkts.ArrowFunctionExpression { return arkts.factory.updateArrowFunction( @@ -264,7 +274,7 @@ export class RewriteFactory { node: arkts.Identifier, metadata?: CachedMetadata ): arkts.Identifier | arkts.MemberExpression { - if (!node.name.startsWith(GenSymPrefix.INTRINSIC) && !node.name.startsWith(GenSymPrefix.UI)) { + if (!node.name.startsWith(BuiltInNames.GENSYM_INTRINSIC_PREFIX) && !node.name.startsWith(BuiltInNames.GENSYM_UI_PREFIX)) { return factory.createMemoParameterAccess(node.name); } return node; diff --git a/arkui-plugins/memo-plugins/parameter-transformer.ts b/arkui-plugins/memo-plugins/parameter-transformer.ts index 8aef0822c..4af68149b 100644 --- a/arkui-plugins/memo-plugins/parameter-transformer.ts +++ b/arkui-plugins/memo-plugins/parameter-transformer.ts @@ -210,7 +210,7 @@ export class ParameterTransformer extends AbstractVisitor { if (!shouldUpdate) { return node; } - const decl = arkts.getPeerDecl(memoInfo.rewritePeer); + const decl = arkts.getPeerIdentifierDecl(memoInfo.rewritePeer); if (!decl || !arkts.isEtsParameterExpression(decl)) { return node; } @@ -245,7 +245,7 @@ export class ParameterTransformer extends AbstractVisitor { return that.updateParamReDeclare(declarator, memoInfo); } if (!!declarator.initializer && arkts.isIdentifier(declarator.initializer)) { - const decl = arkts.getPeerDecl(declarator.initializer.originalPeer); + const decl = arkts.getPeerIdentifierDecl(declarator.initializer.originalPeer); if (decl && that.rewriteIdentifiers?.has(decl.peer)) { return arkts.factory.updateVariableDeclarator( declarator, @@ -282,7 +282,7 @@ export class ParameterTransformer extends AbstractVisitor { return this.updateVariableReDeclarationFromParam(beforeChildren); } if (arkts.isCallExpression(beforeChildren) && arkts.isIdentifier(beforeChildren.expression)) { - const decl = arkts.getPeerDecl(beforeChildren.expression.originalPeer); + const decl = arkts.getPeerIdentifierDecl(beforeChildren.expression.originalPeer); if (decl && this.rewriteCalls?.has(decl.peer)) { const updateCall = this.rewriteCalls.get(decl.peer)!( beforeChildren.arguments.map((it) => this.visitor(it) as arkts.Expression) @@ -296,7 +296,7 @@ export class ParameterTransformer extends AbstractVisitor { } const node = this.visitEachChild(beforeChildren); if (arkts.isIdentifier(node)) { - const decl = arkts.getPeerDecl(node.originalPeer); + const decl = arkts.getPeerIdentifierDecl(node.originalPeer); if (decl && this.rewriteIdentifiers?.has(decl.peer)) { return this.rewriteIdentifiers.get(decl.peer)!(); } diff --git a/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts b/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts index 6261ad5d5..210dd0c69 100644 --- a/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts @@ -60,11 +60,11 @@ import { Prop as Prop, State as State } from "@ohos.arkui.stateManagement"; } @Component() export declare interface __Options_SwipeRefresher { - content?: (ResourceStr | undefined); + @Prop() content?: (ResourceStr | undefined); @Prop() __backing_content?: (ResourceStr | undefined); - isLoading?: boolean; + @Prop() isLoading?: boolean; @Prop() __backing_isLoading?: boolean; - code?: number; + @State() code?: number; @State() __backing_code?: number; } @@ -105,21 +105,21 @@ function main() {} } @Component() export declare interface __Options_SwipeRefresher { - set content(content: ((ResourceStr | undefined) | undefined)) + @Prop() set content(content: ((ResourceStr | undefined) | undefined)) - get content(): ((ResourceStr | undefined) | undefined) + @Prop() get content(): ((ResourceStr | undefined) | undefined) set __backing_content(__backing_content: (IPropDecoratedVariable<(ResourceStr | undefined)> | undefined)) get __backing_content(): (IPropDecoratedVariable<(ResourceStr | undefined)> | undefined) - set isLoading(isLoading: (boolean | undefined)) + @Prop() set isLoading(isLoading: (boolean | undefined)) - get isLoading(): (boolean | undefined) + @Prop() get isLoading(): (boolean | undefined) set __backing_isLoading(__backing_isLoading: (IPropDecoratedVariable | undefined)) get __backing_isLoading(): (IPropDecoratedVariable | undefined) - set code(code: (number | undefined)) + @State() set code(code: (number | undefined)) - get code(): (number | undefined) + @State() get code(): (number | undefined) set __backing_code(__backing_code: (IStateDecoratedVariable | undefined)) get __backing_code(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts index 9b72b4d35..a686e3f07 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts @@ -237,9 +237,9 @@ function main() {} set aaController(aaController: ((CustomDialogController | undefined) | undefined)) get aaController(): ((CustomDialogController | undefined) | undefined) - set text(text: (string | undefined)) + @State() set text(text: (string | undefined)) - get text(): (string | undefined) + @State() get text(): (string | undefined) set __backing_text(__backing_text: (IStateDecoratedVariable | undefined)) get __backing_text(): (IStateDecoratedVariable | undefined) @@ -249,9 +249,9 @@ function main() {} set confirm(confirm: ((()=> void) | undefined)) get confirm(): ((()=> void) | undefined) - set hh(hh: (string | undefined)) + @State() set hh(hh: (string | undefined)) - get hh(): (string | undefined) + @State() get hh(): (string | undefined) set __backing_hh(__backing_hh: (IStateDecoratedVariable | undefined)) get __backing_hh(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts index 04d08c3ea..f183c6f51 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts @@ -153,15 +153,15 @@ function main() {} set aaController(aaController: ((CustomDialogController | undefined) | undefined)) get aaController(): ((CustomDialogController | undefined) | undefined) - set text(text: (string | undefined)) + @State() set text(text: (string | undefined)) - get text(): (string | undefined) + @State() get text(): (string | undefined) set __backing_text(__backing_text: (IStateDecoratedVariable | undefined)) get __backing_text(): (IStateDecoratedVariable | undefined) - set hh(hh: (string | undefined)) + @State() set hh(hh: (string | undefined)) - get hh(): (string | undefined) + @State() get hh(): (string | undefined) set __backing_hh(__backing_hh: (IStateDecoratedVariable | undefined)) get __backing_hh(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts index 62f3f08e2..d0e8eb280 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts @@ -140,36 +140,34 @@ function main() {} } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_LinkParent { - @__Link_intrinsic() set linkVar1(linkVar1: (string | undefined)) + @Link() set linkVar1(linkVar1: (string | undefined)) - @__Link_intrinsic() get linkVar1(): (string | undefined) + @Link() get linkVar1(): (string | undefined) set __backing_linkVar1(__backing_linkVar1: (LinkSourceType | undefined)) get __backing_linkVar1(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar2(linkVar2: (number | undefined)) + @Link() set linkVar2(linkVar2: (number | undefined)) - @__Link_intrinsic() get linkVar2(): (number | undefined) + @Link() get linkVar2(): (number | undefined) set __backing_linkVar2(__backing_linkVar2: (LinkSourceType | undefined)) get __backing_linkVar2(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar3(linkVar3: (boolean | undefined)) + @Link() set linkVar3(linkVar3: (boolean | undefined)) - @__Link_intrinsic() get linkVar3(): (boolean | undefined) + @Link() get linkVar3(): (boolean | undefined) set __backing_linkVar3(__backing_linkVar3: (LinkSourceType | undefined)) get __backing_linkVar3(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar4(linkVar4: (undefined | undefined)) + @Link() set linkVar4(linkVar4: (undefined | undefined)) - @__Link_intrinsic() get linkVar4(): (undefined | undefined) + @Link() get linkVar4(): (undefined | undefined) set __backing_linkVar4(__backing_linkVar4: (LinkSourceType | undefined)) get __backing_linkVar4(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar5(linkVar5: (null | undefined)) + @Link() set linkVar5(linkVar5: (null | undefined)) - @__Link_intrinsic() get linkVar5(): (null | undefined) + @Link() get linkVar5(): (null | undefined) set __backing_linkVar5(__backing_linkVar5: (LinkSourceType | undefined)) get __backing_linkVar5(): (LinkSourceType | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts index bd0b32e4b..8eaa4a762 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts @@ -312,78 +312,76 @@ final class LinkType extends BaseEnum { } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_Parent { - @__Link_intrinsic() set linkVar1(linkVar1: (Per | undefined)) + @Link() set linkVar1(linkVar1: (Per | undefined)) - @__Link_intrinsic() get linkVar1(): (Per | undefined) + @Link() get linkVar1(): (Per | undefined) set __backing_linkVar1(__backing_linkVar1: (LinkSourceType | undefined)) get __backing_linkVar1(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar2(linkVar2: (Array | undefined)) + @Link() set linkVar2(linkVar2: (Array | undefined)) - @__Link_intrinsic() get linkVar2(): (Array | undefined) + @Link() get linkVar2(): (Array | undefined) set __backing_linkVar2(__backing_linkVar2: (LinkSourceType> | undefined)) get __backing_linkVar2(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar3(linkVar3: (LinkType | undefined)) + @Link() set linkVar3(linkVar3: (LinkType | undefined)) - @__Link_intrinsic() get linkVar3(): (LinkType | undefined) + @Link() get linkVar3(): (LinkType | undefined) set __backing_linkVar3(__backing_linkVar3: (LinkSourceType | undefined)) get __backing_linkVar3(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar4(linkVar4: (Set | undefined)) + @Link() set linkVar4(linkVar4: (Set | undefined)) - @__Link_intrinsic() get linkVar4(): (Set | undefined) + @Link() get linkVar4(): (Set | undefined) set __backing_linkVar4(__backing_linkVar4: (LinkSourceType> | undefined)) get __backing_linkVar4(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar5(linkVar5: (Array | undefined)) + @Link() set linkVar5(linkVar5: (Array | undefined)) - @__Link_intrinsic() get linkVar5(): (Array | undefined) + @Link() get linkVar5(): (Array | undefined) set __backing_linkVar5(__backing_linkVar5: (LinkSourceType> | undefined)) get __backing_linkVar5(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar6(linkVar6: (Array | undefined)) + @Link() set linkVar6(linkVar6: (Array | undefined)) - @__Link_intrinsic() get linkVar6(): (Array | undefined) + @Link() get linkVar6(): (Array | undefined) set __backing_linkVar6(__backing_linkVar6: (LinkSourceType> | undefined)) get __backing_linkVar6(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar7(linkVar7: (Array | undefined)) + @Link() set linkVar7(linkVar7: (Array | undefined)) - @__Link_intrinsic() get linkVar7(): (Array | undefined) + @Link() get linkVar7(): (Array | undefined) set __backing_linkVar7(__backing_linkVar7: (LinkSourceType> | undefined)) get __backing_linkVar7(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar8(linkVar8: (((sr: string)=> void) | undefined)) + @Link() set linkVar8(linkVar8: (((sr: string)=> void) | undefined)) - @__Link_intrinsic() get linkVar8(): (((sr: string)=> void) | undefined) + @Link() get linkVar8(): (((sr: string)=> void) | undefined) set __backing_linkVar8(__backing_linkVar8: (LinkSourceType<((sr: string)=> void)> | undefined)) get __backing_linkVar8(): (LinkSourceType<((sr: string)=> void)> | undefined) - @__Link_intrinsic() set linkVar9(linkVar9: (Date | undefined)) + @Link() set linkVar9(linkVar9: (Date | undefined)) - @__Link_intrinsic() get linkVar9(): (Date | undefined) + @Link() get linkVar9(): (Date | undefined) set __backing_linkVar9(__backing_linkVar9: (LinkSourceType | undefined)) get __backing_linkVar9(): (LinkSourceType | undefined) - @__Link_intrinsic() set linkVar10(linkVar10: (Map | undefined)) + @Link() set linkVar10(linkVar10: (Map | undefined)) - @__Link_intrinsic() get linkVar10(): (Map | undefined) + @Link() get linkVar10(): (Map | undefined) set __backing_linkVar10(__backing_linkVar10: (LinkSourceType> | undefined)) get __backing_linkVar10(): (LinkSourceType> | undefined) - @__Link_intrinsic() set linkVar11(linkVar11: ((string | number) | undefined)) + @Link() set linkVar11(linkVar11: ((string | number) | undefined)) - @__Link_intrinsic() get linkVar11(): ((string | number) | undefined) + @Link() get linkVar11(): ((string | number) | undefined) set __backing_linkVar11(__backing_linkVar11: (LinkSourceType<(string | number)> | undefined)) get __backing_linkVar11(): (LinkSourceType<(string | number)> | undefined) - @__Link_intrinsic() set linkVar12(linkVar12: ((Set | Per) | undefined)) + @Link() set linkVar12(linkVar12: ((Set | Per) | undefined)) - @__Link_intrinsic() get linkVar12(): ((Set | Per) | undefined) + @Link() get linkVar12(): ((Set | Per) | undefined) set __backing_linkVar12(__backing_linkVar12: (LinkSourceType<(Set | Per)> | undefined)) get __backing_linkVar12(): (LinkSourceType<(Set | Per)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts index 0e3f56d43..3ef198fa2 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts @@ -173,12 +173,10 @@ function main() {} } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_Parant { - @__Link_intrinsic() set text1(text1: (string | undefined)) + @Link() set text1(text1: (string | undefined)) - @__Link_intrinsic() get text1(): (string | undefined) + @Link() get text1(): (string | undefined) set __backing_text1(__backing_text1: (LinkSourceType | undefined)) get __backing_text1(): (LinkSourceType | undefined) @@ -186,27 +184,27 @@ function main() {} } @Component() export interface __Options_Child { - @__Link_intrinsic() set childText(childText: (string | undefined)) + @Link() set childText(childText: (string | undefined)) - @__Link_intrinsic() get childText(): (string | undefined) + @Link() get childText(): (string | undefined) set __backing_childText(__backing_childText: (LinkSourceType | undefined)) get __backing_childText(): (LinkSourceType | undefined) - set childText2(childText2: (string | undefined)) + @State() set childText2(childText2: (string | undefined)) - get childText2(): (string | undefined) + @State() get childText2(): (string | undefined) set __backing_childText2(__backing_childText2: (IStateDecoratedVariable | undefined)) get __backing_childText2(): (IStateDecoratedVariable | undefined) - set childText3(childText3: (string | undefined)) + @Prop() set childText3(childText3: (string | undefined)) - get childText3(): (string | undefined) + @Prop() get childText3(): (string | undefined) set __backing_childText3(__backing_childText3: (IPropDecoratedVariable | undefined)) get __backing_childText3(): (IPropDecoratedVariable | undefined) - set childText4(childText4: (string | undefined)) + @Prop() set childText4(childText4: (string | undefined)) - get childText4(): (string | undefined) + @Prop() get childText4(): (string | undefined) set __backing_childText4(__backing_childText4: (IPropDecoratedVariable | undefined)) get __backing_childText4(): (IPropDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts index 8f4d4fa0e..d39b4527b 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts @@ -168,12 +168,10 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_DateComponent { - @__Link_intrinsic() set selectedDate(selectedDate: (Date | undefined)) + @Link() set selectedDate(selectedDate: (Date | undefined)) - @__Link_intrinsic() get selectedDate(): (Date | undefined) + @Link() get selectedDate(): (Date | undefined) set __backing_selectedDate(__backing_selectedDate: (LinkSourceType | undefined)) get __backing_selectedDate(): (LinkSourceType | undefined) @@ -181,9 +179,9 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_ParentComponent { - set parentSelectedDate(parentSelectedDate: (Date | undefined)) + @State() set parentSelectedDate(parentSelectedDate: (Date | undefined)) - get parentSelectedDate(): (Date | undefined) + @State() get parentSelectedDate(): (Date | undefined) set __backing_parentSelectedDate(__backing_parentSelectedDate: (IStateDecoratedVariable | undefined)) get __backing_parentSelectedDate(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts index f3261d45b..feb806836 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts @@ -233,45 +233,45 @@ final class Status extends BaseEnum { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set arrayA(arrayA: (Array | undefined)) + @LocalStorageLink({value:"Prop1"}) set arrayA(arrayA: (Array | undefined)) - get arrayA(): (Array | undefined) + @LocalStorageLink({value:"Prop1"}) get arrayA(): (Array | undefined) set __backing_arrayA(__backing_arrayA: (ILocalStorageLinkDecoratedVariable> | undefined)) get __backing_arrayA(): (ILocalStorageLinkDecoratedVariable> | undefined) - set objectA(objectA: (Object | undefined)) + @LocalStorageLink({value:"Prop2"}) set objectA(objectA: (Object | undefined)) - get objectA(): (Object | undefined) + @LocalStorageLink({value:"Prop2"}) get objectA(): (Object | undefined) set __backing_objectA(__backing_objectA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_objectA(): (ILocalStorageLinkDecoratedVariable | undefined) - set dateA(dateA: (Date | undefined)) + @LocalStorageLink({value:"Prop3"}) set dateA(dateA: (Date | undefined)) - get dateA(): (Date | undefined) + @LocalStorageLink({value:"Prop3"}) get dateA(): (Date | undefined) set __backing_dateA(__backing_dateA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_dateA(): (ILocalStorageLinkDecoratedVariable | undefined) - set setA(setA: (Set | undefined)) + @LocalStorageLink({value:"Prop4"}) set setA(setA: (Set | undefined)) - get setA(): (Set | undefined) + @LocalStorageLink({value:"Prop4"}) get setA(): (Set | undefined) set __backing_setA(__backing_setA: (ILocalStorageLinkDecoratedVariable> | undefined)) get __backing_setA(): (ILocalStorageLinkDecoratedVariable> | undefined) - set mapA(mapA: (Map | undefined)) + @LocalStorageLink({value:"Prop5"}) set mapA(mapA: (Map | undefined)) - get mapA(): (Map | undefined) + @LocalStorageLink({value:"Prop5"}) get mapA(): (Map | undefined) set __backing_mapA(__backing_mapA: (ILocalStorageLinkDecoratedVariable> | undefined)) get __backing_mapA(): (ILocalStorageLinkDecoratedVariable> | undefined) - set classA(classA: (Person | undefined)) + @LocalStorageLink({value:"Prop7"}) set classA(classA: (Person | undefined)) - get classA(): (Person | undefined) + @LocalStorageLink({value:"Prop7"}) get classA(): (Person | undefined) set __backing_classA(__backing_classA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_classA(): (ILocalStorageLinkDecoratedVariable | undefined) - set enumA(enumA: (Status | undefined)) + @LocalStorageLink({value:"Prop8"}) set enumA(enumA: (Status | undefined)) - get enumA(): (Status | undefined) + @LocalStorageLink({value:"Prop8"}) get enumA(): (Status | undefined) set __backing_enumA(__backing_enumA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_enumA(): (ILocalStorageLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts index 507a09fe3..9473dc5bb 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts @@ -113,21 +113,21 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set numA(numA: (number | undefined)) + @LocalStorageLink({value:"Prop1"}) set numA(numA: (number | undefined)) - get numA(): (number | undefined) + @LocalStorageLink({value:"Prop1"}) get numA(): (number | undefined) set __backing_numA(__backing_numA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_numA(): (ILocalStorageLinkDecoratedVariable | undefined) - set stringA(stringA: (string | undefined)) + @LocalStorageLink({value:"Prop2"}) set stringA(stringA: (string | undefined)) - get stringA(): (string | undefined) + @LocalStorageLink({value:"Prop2"}) get stringA(): (string | undefined) set __backing_stringA(__backing_stringA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_stringA(): (ILocalStorageLinkDecoratedVariable | undefined) - set booleanA(booleanA: (boolean | undefined)) + @LocalStorageLink({value:"Prop3"}) set booleanA(booleanA: (boolean | undefined)) - get booleanA(): (boolean | undefined) + @LocalStorageLink({value:"Prop3"}) get booleanA(): (boolean | undefined) set __backing_booleanA(__backing_booleanA: (ILocalStorageLinkDecoratedVariable | undefined)) get __backing_booleanA(): (ILocalStorageLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts index c52fc3620..0e1071316 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts @@ -217,45 +217,45 @@ final class Status extends BaseEnum { } @Component() export interface __Options_MyStateSample { - set arrayB(arrayB: (Array | undefined)) + @LocalStoragePropRef({value:"Prop1"}) set arrayB(arrayB: (Array | undefined)) - get arrayB(): (Array | undefined) + @LocalStoragePropRef({value:"Prop1"}) get arrayB(): (Array | undefined) set __backing_arrayB(__backing_arrayB: (ILocalStoragePropRefDecoratedVariable> | undefined)) get __backing_arrayB(): (ILocalStoragePropRefDecoratedVariable> | undefined) - set objectB(objectB: (Object | undefined)) + @LocalStoragePropRef({value:"Prop2"}) set objectB(objectB: (Object | undefined)) - get objectB(): (Object | undefined) + @LocalStoragePropRef({value:"Prop2"}) get objectB(): (Object | undefined) set __backing_objectB(__backing_objectB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_objectB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set dateB(dateB: (Date | undefined)) + @LocalStoragePropRef({value:"Prop3"}) set dateB(dateB: (Date | undefined)) - get dateB(): (Date | undefined) + @LocalStoragePropRef({value:"Prop3"}) get dateB(): (Date | undefined) set __backing_dateB(__backing_dateB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_dateB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set setB(setB: (Set | undefined)) + @LocalStoragePropRef({value:"Prop4"}) set setB(setB: (Set | undefined)) - get setB(): (Set | undefined) + @LocalStoragePropRef({value:"Prop4"}) get setB(): (Set | undefined) set __backing_setB(__backing_setB: (ILocalStoragePropRefDecoratedVariable> | undefined)) get __backing_setB(): (ILocalStoragePropRefDecoratedVariable> | undefined) - set mapB(mapB: (Map | undefined)) + @LocalStoragePropRef({value:"Prop5"}) set mapB(mapB: (Map | undefined)) - get mapB(): (Map | undefined) + @LocalStoragePropRef({value:"Prop5"}) get mapB(): (Map | undefined) set __backing_mapB(__backing_mapB: (ILocalStoragePropRefDecoratedVariable> | undefined)) get __backing_mapB(): (ILocalStoragePropRefDecoratedVariable> | undefined) - set classB(classB: (Person | undefined)) + @LocalStoragePropRef({value:"Prop7"}) set classB(classB: (Person | undefined)) - get classB(): (Person | undefined) + @LocalStoragePropRef({value:"Prop7"}) get classB(): (Person | undefined) set __backing_classB(__backing_classB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_classB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set enumB(enumB: (Status | undefined)) + @LocalStoragePropRef({value:"Prop8"}) set enumB(enumB: (Status | undefined)) - get enumB(): (Status | undefined) + @LocalStoragePropRef({value:"Prop8"}) get enumB(): (Status | undefined) set __backing_enumB(__backing_enumB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_enumB(): (ILocalStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts index 14e3191b4..08c63f237 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts @@ -120,33 +120,33 @@ function main() {} } @Component() export interface __Options_MyStateSample { - set numB(numB: (number | undefined)) + @LocalStoragePropRef({value:"Prop1"}) set numB(numB: (number | undefined)) - get numB(): (number | undefined) + @LocalStoragePropRef({value:"Prop1"}) get numB(): (number | undefined) set __backing_numB(__backing_numB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_numB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set stringB(stringB: (string | undefined)) + @LocalStoragePropRef({value:"Prop2"}) set stringB(stringB: (string | undefined)) - get stringB(): (string | undefined) + @LocalStoragePropRef({value:"Prop2"}) get stringB(): (string | undefined) set __backing_stringB(__backing_stringB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_stringB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set booleanB(booleanB: (boolean | undefined)) + @LocalStoragePropRef({value:"Prop3"}) set booleanB(booleanB: (boolean | undefined)) - get booleanB(): (boolean | undefined) + @LocalStoragePropRef({value:"Prop3"}) get booleanB(): (boolean | undefined) set __backing_booleanB(__backing_booleanB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_booleanB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set undefinedB(undefinedB: (undefined | undefined)) + @LocalStoragePropRef({value:"Prop4"}) set undefinedB(undefinedB: (undefined | undefined)) - get undefinedB(): (undefined | undefined) + @LocalStoragePropRef({value:"Prop4"}) get undefinedB(): (undefined | undefined) set __backing_undefinedB(__backing_undefinedB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_undefinedB(): (ILocalStoragePropRefDecoratedVariable | undefined) - set nullB(nullB: (null | undefined)) + @LocalStoragePropRef({value:"Prop5"}) set nullB(nullB: (null | undefined)) - get nullB(): (null | undefined) + @LocalStoragePropRef({value:"Prop5"}) get nullB(): (null | undefined) set __backing_nullB(__backing_nullB: (ILocalStoragePropRefDecoratedVariable | undefined)) get __backing_nullB(): (ILocalStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts index 9bace1f47..0d9635769 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts @@ -126,9 +126,9 @@ function main() {} } @Component() export interface __Options_MyStateSample { - set objectlinkvar(objectlinkvar: (A | undefined)) + @ObjectLink() set objectlinkvar(objectlinkvar: (A | undefined)) - get objectlinkvar(): (A | undefined) + @ObjectLink() get objectlinkvar(): (A | undefined) set __backing_objectlinkvar(__backing_objectlinkvar: (IObjectLinkDecoratedVariable | undefined)) get __backing_objectlinkvar(): (IObjectLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts index 1b4c2aad5..b297a05da 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts @@ -263,9 +263,9 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ set label(label: (string | undefined)) get label(): (string | undefined) - set data(data: (DateClass | undefined)) + @ObjectLink() set data(data: (DateClass | undefined)) - get data(): (DateClass | undefined) + @ObjectLink() get data(): (DateClass | undefined) set __backing_data(__backing_data: (IObjectLinkDecoratedVariable | undefined)) get __backing_data(): (IObjectLinkDecoratedVariable | undefined) @@ -273,9 +273,9 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Parent { - set newData(newData: (NewDate | undefined)) + @State() set newData(newData: (NewDate | undefined)) - get newData(): (NewDate | undefined) + @State() get newData(): (NewDate | undefined) set __backing_newData(__backing_newData: (IStateDecoratedVariable | undefined)) get __backing_newData(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts index b788197b5..0ec50ded0 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts @@ -148,33 +148,33 @@ function main() {} } @Component() export interface __Options_PropParent { - set propVar1(propVar1: (string | undefined)) + @PropRef() set propVar1(propVar1: (string | undefined)) - get propVar1(): (string | undefined) + @PropRef() get propVar1(): (string | undefined) set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) - set propVar2(propVar2: (number | undefined)) + @PropRef() set propVar2(propVar2: (number | undefined)) - get propVar2(): (number | undefined) + @PropRef() get propVar2(): (number | undefined) set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable | undefined)) get __backing_propVar2(): (IPropRefDecoratedVariable | undefined) - set propVar3(propVar3: (boolean | undefined)) + @PropRef() set propVar3(propVar3: (boolean | undefined)) - get propVar3(): (boolean | undefined) + @PropRef() get propVar3(): (boolean | undefined) set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) - set propVar4(propVar4: (undefined | undefined)) + @PropRef() set propVar4(propVar4: (undefined | undefined)) - get propVar4(): (undefined | undefined) + @PropRef() get propVar4(): (undefined | undefined) set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable | undefined)) get __backing_propVar4(): (IPropRefDecoratedVariable | undefined) - set propVar5(propVar5: (null | undefined)) + @PropRef() set propVar5(propVar5: (null | undefined)) - get propVar5(): (null | undefined) + @PropRef() get propVar5(): (null | undefined) set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable | undefined)) get __backing_propVar5(): (IPropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts index a0a73384b..9b47cd481 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts @@ -335,75 +335,75 @@ final class PropType extends BaseEnum { } @Component() export interface __Options_Parent { - set propVar1(propVar1: (Per | undefined)) + @PropRef() set propVar1(propVar1: (Per | undefined)) - get propVar1(): (Per | undefined) + @PropRef() get propVar1(): (Per | undefined) set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) - set propVar2(propVar2: (Array | undefined)) + @PropRef() set propVar2(propVar2: (Array | undefined)) - get propVar2(): (Array | undefined) + @PropRef() get propVar2(): (Array | undefined) set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar2(): (IPropRefDecoratedVariable> | undefined) - set propVar3(propVar3: (PropType | undefined)) + @PropRef() set propVar3(propVar3: (PropType | undefined)) - get propVar3(): (PropType | undefined) + @PropRef() get propVar3(): (PropType | undefined) set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) - set propVar4(propVar4: (Set | undefined)) + @PropRef() set propVar4(propVar4: (Set | undefined)) - get propVar4(): (Set | undefined) + @PropRef() get propVar4(): (Set | undefined) set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar4(): (IPropRefDecoratedVariable> | undefined) - set propVar5(propVar5: (Array | undefined)) + @PropRef() set propVar5(propVar5: (Array | undefined)) - get propVar5(): (Array | undefined) + @PropRef() get propVar5(): (Array | undefined) set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar5(): (IPropRefDecoratedVariable> | undefined) - set propVar6(propVar6: (Array | undefined)) + @PropRef() set propVar6(propVar6: (Array | undefined)) - get propVar6(): (Array | undefined) + @PropRef() get propVar6(): (Array | undefined) set __backing_propVar6(__backing_propVar6: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar6(): (IPropRefDecoratedVariable> | undefined) - set propVar7(propVar7: (Array | undefined)) + @PropRef() set propVar7(propVar7: (Array | undefined)) - get propVar7(): (Array | undefined) + @PropRef() get propVar7(): (Array | undefined) set __backing_propVar7(__backing_propVar7: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar7(): (IPropRefDecoratedVariable> | undefined) - set propVar8(propVar8: (((sr: string)=> void) | undefined)) + @PropRef() set propVar8(propVar8: (((sr: string)=> void) | undefined)) - get propVar8(): (((sr: string)=> void) | undefined) + @PropRef() get propVar8(): (((sr: string)=> void) | undefined) set __backing_propVar8(__backing_propVar8: (IPropRefDecoratedVariable<((sr: string)=> void)> | undefined)) get __backing_propVar8(): (IPropRefDecoratedVariable<((sr: string)=> void)> | undefined) - set propVar9(propVar9: (Date | undefined)) + @PropRef() set propVar9(propVar9: (Date | undefined)) - get propVar9(): (Date | undefined) + @PropRef() get propVar9(): (Date | undefined) set __backing_propVar9(__backing_propVar9: (IPropRefDecoratedVariable | undefined)) get __backing_propVar9(): (IPropRefDecoratedVariable | undefined) - set propVar10(propVar10: (Map | undefined)) + @PropRef() set propVar10(propVar10: (Map | undefined)) - get propVar10(): (Map | undefined) + @PropRef() get propVar10(): (Map | undefined) set __backing_propVar10(__backing_propVar10: (IPropRefDecoratedVariable> | undefined)) get __backing_propVar10(): (IPropRefDecoratedVariable> | undefined) - set propVar11(propVar11: ((string | number) | undefined)) + @PropRef() set propVar11(propVar11: ((string | number) | undefined)) - get propVar11(): ((string | number) | undefined) + @PropRef() get propVar11(): ((string | number) | undefined) set __backing_propVar11(__backing_propVar11: (IPropRefDecoratedVariable<(string | number)> | undefined)) get __backing_propVar11(): (IPropRefDecoratedVariable<(string | number)> | undefined) - set propVar12(propVar12: ((Set | Per) | undefined)) + @PropRef() set propVar12(propVar12: ((Set | Per) | undefined)) - get propVar12(): ((Set | Per) | undefined) + @PropRef() get propVar12(): ((Set | Per) | undefined) set __backing_propVar12(__backing_propVar12: (IPropRefDecoratedVariable<(Set | Per)> | undefined)) get __backing_propVar12(): (IPropRefDecoratedVariable<(Set | Per)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts index c078ab437..f2b2c10eb 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts @@ -66,19 +66,19 @@ import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; } @Component() export interface __Options_PropParent { - propVar1?: string; + @PropRef() propVar1?: string; @PropRef() __backing_propVar1?: string; - propVar2?: (number | undefined); + @PropRef() propVar2?: (number | undefined); @PropRef() __backing_propVar2?: (number | undefined); - propVar3?: boolean; + @PropRef() propVar3?: boolean; @PropRef() __backing_propVar3?: boolean; - propVar4?: undefined; + @PropRef() propVar4?: undefined; @PropRef() __backing_propVar4?: undefined; - propVar5?: null; + @PropRef() propVar5?: null; @PropRef() __backing_propVar5?: null; - propVar6?: (Array | null); + @PropRef() propVar6?: (Array | null); @PropRef() __backing_propVar6?: (Array | null); - propVar7?: (Map | undefined); + @PropRef() propVar7?: (Map | undefined); @PropRef() __backing_propVar7?: (Map | undefined); } @@ -218,45 +218,45 @@ function main() {} } @Component() export interface __Options_PropParent { - set propVar1(propVar1: (string | undefined)) + @PropRef() set propVar1(propVar1: (string | undefined)) - get propVar1(): (string | undefined) + @PropRef() get propVar1(): (string | undefined) set __backing_propVar1(__backing_propVar1: (IPropRefDecoratedVariable | undefined)) get __backing_propVar1(): (IPropRefDecoratedVariable | undefined) - set propVar2(propVar2: ((number | undefined) | undefined)) + @PropRef() set propVar2(propVar2: ((number | undefined) | undefined)) - get propVar2(): ((number | undefined) | undefined) + @PropRef() get propVar2(): ((number | undefined) | undefined) set __backing_propVar2(__backing_propVar2: (IPropRefDecoratedVariable<(number | undefined)> | undefined)) get __backing_propVar2(): (IPropRefDecoratedVariable<(number | undefined)> | undefined) - set propVar3(propVar3: (boolean | undefined)) + @PropRef() set propVar3(propVar3: (boolean | undefined)) - get propVar3(): (boolean | undefined) + @PropRef() get propVar3(): (boolean | undefined) set __backing_propVar3(__backing_propVar3: (IPropRefDecoratedVariable | undefined)) get __backing_propVar3(): (IPropRefDecoratedVariable | undefined) - set propVar4(propVar4: (undefined | undefined)) + @PropRef() set propVar4(propVar4: (undefined | undefined)) - get propVar4(): (undefined | undefined) + @PropRef() get propVar4(): (undefined | undefined) set __backing_propVar4(__backing_propVar4: (IPropRefDecoratedVariable | undefined)) get __backing_propVar4(): (IPropRefDecoratedVariable | undefined) - set propVar5(propVar5: (null | undefined)) + @PropRef() set propVar5(propVar5: (null | undefined)) - get propVar5(): (null | undefined) + @PropRef() get propVar5(): (null | undefined) set __backing_propVar5(__backing_propVar5: (IPropRefDecoratedVariable | undefined)) get __backing_propVar5(): (IPropRefDecoratedVariable | undefined) - set propVar6(propVar6: ((Array | null) | undefined)) + @PropRef() set propVar6(propVar6: ((Array | null) | undefined)) - get propVar6(): ((Array | null) | undefined) + @PropRef() get propVar6(): ((Array | null) | undefined) set __backing_propVar6(__backing_propVar6: (IPropRefDecoratedVariable<(Array | null)> | undefined)) get __backing_propVar6(): (IPropRefDecoratedVariable<(Array | null)> | undefined) - set propVar7(propVar7: ((Map | undefined) | undefined)) + @PropRef() set propVar7(propVar7: ((Map | undefined) | undefined)) - get propVar7(): ((Map | undefined) | undefined) + @PropRef() get propVar7(): ((Map | undefined) | undefined) set __backing_propVar7(__backing_propVar7: (IPropRefDecoratedVariable<(Map | undefined)> | undefined)) get __backing_propVar7(): (IPropRefDecoratedVariable<(Map | undefined)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts index 1cc5db07d..89c427e15 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts @@ -168,9 +168,9 @@ function main() {} } @Component() export interface __Options_CountDownComponent { - set count(count: (number | undefined)) + @PropRef() set count(count: (number | undefined)) - get count(): (number | undefined) + @PropRef() get count(): (number | undefined) set __backing_count(__backing_count: (IPropRefDecoratedVariable | undefined)) get __backing_count(): (IPropRefDecoratedVariable | undefined) @@ -181,9 +181,9 @@ function main() {} } @Component() export interface __Options_ParentComponent { - set countDownStartValue(countDownStartValue: (number | undefined)) + @State() set countDownStartValue(countDownStartValue: (number | undefined)) - get countDownStartValue(): (number | undefined) + @State() get countDownStartValue(): (number | undefined) set __backing_countDownStartValue(__backing_countDownStartValue: (IStateDecoratedVariable | undefined)) get __backing_countDownStartValue(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts index d8584fd5f..a51175b8b 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts @@ -149,33 +149,33 @@ function main() {} } @Component() export interface __Options_PropParent { - set propVar1(propVar1: (string | undefined)) + @Prop() set propVar1(propVar1: (string | undefined)) - get propVar1(): (string | undefined) + @Prop() get propVar1(): (string | undefined) set __backing_propVar1(__backing_propVar1: (IPropDecoratedVariable | undefined)) get __backing_propVar1(): (IPropDecoratedVariable | undefined) - set propVar2(propVar2: (number | undefined)) + @Prop() set propVar2(propVar2: (number | undefined)) - get propVar2(): (number | undefined) + @Prop() get propVar2(): (number | undefined) set __backing_propVar2(__backing_propVar2: (IPropDecoratedVariable | undefined)) get __backing_propVar2(): (IPropDecoratedVariable | undefined) - set propVar3(propVar3: (boolean | undefined)) + @Prop() set propVar3(propVar3: (boolean | undefined)) - get propVar3(): (boolean | undefined) + @Prop() get propVar3(): (boolean | undefined) set __backing_propVar3(__backing_propVar3: (IPropDecoratedVariable | undefined)) get __backing_propVar3(): (IPropDecoratedVariable | undefined) - set propVar4(propVar4: (undefined | undefined)) + @Prop() set propVar4(propVar4: (undefined | undefined)) - get propVar4(): (undefined | undefined) + @Prop() get propVar4(): (undefined | undefined) set __backing_propVar4(__backing_propVar4: (IPropDecoratedVariable | undefined)) get __backing_propVar4(): (IPropDecoratedVariable | undefined) - set propVar5(propVar5: (null | undefined)) + @Prop() set propVar5(propVar5: (null | undefined)) - get propVar5(): (null | undefined) + @Prop() get propVar5(): (null | undefined) set __backing_propVar5(__backing_propVar5: (IPropDecoratedVariable | undefined)) get __backing_propVar5(): (IPropDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts index e108af26c..ef4a50a29 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts @@ -336,75 +336,75 @@ final class PropType extends BaseEnum { } @Component() export interface __Options_Parent { - set propVar1(propVar1: (Per | undefined)) + @Prop() set propVar1(propVar1: (Per | undefined)) - get propVar1(): (Per | undefined) + @Prop() get propVar1(): (Per | undefined) set __backing_propVar1(__backing_propVar1: (IPropDecoratedVariable | undefined)) get __backing_propVar1(): (IPropDecoratedVariable | undefined) - set propVar2(propVar2: (Array | undefined)) + @Prop() set propVar2(propVar2: (Array | undefined)) - get propVar2(): (Array | undefined) + @Prop() get propVar2(): (Array | undefined) set __backing_propVar2(__backing_propVar2: (IPropDecoratedVariable> | undefined)) get __backing_propVar2(): (IPropDecoratedVariable> | undefined) - set propVar3(propVar3: (PropType | undefined)) + @Prop() set propVar3(propVar3: (PropType | undefined)) - get propVar3(): (PropType | undefined) + @Prop() get propVar3(): (PropType | undefined) set __backing_propVar3(__backing_propVar3: (IPropDecoratedVariable | undefined)) get __backing_propVar3(): (IPropDecoratedVariable | undefined) - set propVar4(propVar4: (Set | undefined)) + @Prop() set propVar4(propVar4: (Set | undefined)) - get propVar4(): (Set | undefined) + @Prop() get propVar4(): (Set | undefined) set __backing_propVar4(__backing_propVar4: (IPropDecoratedVariable> | undefined)) get __backing_propVar4(): (IPropDecoratedVariable> | undefined) - set propVar5(propVar5: (Array | undefined)) + @Prop() set propVar5(propVar5: (Array | undefined)) - get propVar5(): (Array | undefined) + @Prop() get propVar5(): (Array | undefined) set __backing_propVar5(__backing_propVar5: (IPropDecoratedVariable> | undefined)) get __backing_propVar5(): (IPropDecoratedVariable> | undefined) - set propVar6(propVar6: (Array | undefined)) + @Prop() set propVar6(propVar6: (Array | undefined)) - get propVar6(): (Array | undefined) + @Prop() get propVar6(): (Array | undefined) set __backing_propVar6(__backing_propVar6: (IPropDecoratedVariable> | undefined)) get __backing_propVar6(): (IPropDecoratedVariable> | undefined) - set propVar7(propVar7: (Array | undefined)) + @Prop() set propVar7(propVar7: (Array | undefined)) - get propVar7(): (Array | undefined) + @Prop() get propVar7(): (Array | undefined) set __backing_propVar7(__backing_propVar7: (IPropDecoratedVariable> | undefined)) get __backing_propVar7(): (IPropDecoratedVariable> | undefined) - set propVar8(propVar8: (((sr: string)=> void) | undefined)) + @Prop() set propVar8(propVar8: (((sr: string)=> void) | undefined)) - get propVar8(): (((sr: string)=> void) | undefined) + @Prop() get propVar8(): (((sr: string)=> void) | undefined) set __backing_propVar8(__backing_propVar8: (IPropDecoratedVariable<((sr: string)=> void)> | undefined)) get __backing_propVar8(): (IPropDecoratedVariable<((sr: string)=> void)> | undefined) - set propVar9(propVar9: (Date | undefined)) + @Prop() set propVar9(propVar9: (Date | undefined)) - get propVar9(): (Date | undefined) + @Prop() get propVar9(): (Date | undefined) set __backing_propVar9(__backing_propVar9: (IPropDecoratedVariable | undefined)) get __backing_propVar9(): (IPropDecoratedVariable | undefined) - set propVar10(propVar10: (Map | undefined)) + @Prop() set propVar10(propVar10: (Map | undefined)) - get propVar10(): (Map | undefined) + @Prop() get propVar10(): (Map | undefined) set __backing_propVar10(__backing_propVar10: (IPropDecoratedVariable> | undefined)) get __backing_propVar10(): (IPropDecoratedVariable> | undefined) - set propVar11(propVar11: ((string | number) | undefined)) + @Prop() set propVar11(propVar11: ((string | number) | undefined)) - get propVar11(): ((string | number) | undefined) + @Prop() get propVar11(): ((string | number) | undefined) set __backing_propVar11(__backing_propVar11: (IPropDecoratedVariable<(string | number)> | undefined)) get __backing_propVar11(): (IPropDecoratedVariable<(string | number)> | undefined) - set propVar12(propVar12: ((Set | Per) | undefined)) + @Prop() set propVar12(propVar12: ((Set | Per) | undefined)) - get propVar12(): ((Set | Per) | undefined) + @Prop() get propVar12(): ((Set | Per) | undefined) set __backing_propVar12(__backing_propVar12: (IPropDecoratedVariable<(Set | Per)> | undefined)) get __backing_propVar12(): (IPropDecoratedVariable<(Set | Per)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts index fb8f9e78c..8f474f700 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts @@ -168,9 +168,9 @@ function main() {} } @Component() export interface __Options_CountDownComponent { - set count(count: (number | undefined)) + @Prop() set count(count: (number | undefined)) - get count(): (number | undefined) + @Prop() get count(): (number | undefined) set __backing_count(__backing_count: (IPropDecoratedVariable | undefined)) get __backing_count(): (IPropDecoratedVariable | undefined) @@ -181,9 +181,9 @@ function main() {} } @Component() export interface __Options_ParentComponent { - set countDownStartValue(countDownStartValue: (number | undefined)) + @State() set countDownStartValue(countDownStartValue: (number | undefined)) - get countDownStartValue(): (number | undefined) + @State() get countDownStartValue(): (number | undefined) set __backing_countDownStartValue(__backing_countDownStartValue: (IStateDecoratedVariable | undefined)) get __backing_countDownStartValue(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts index 453a2c24a..aacb5ed61 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts @@ -162,51 +162,51 @@ function main() {} } @Component() export interface __Options_Ancestors { - set count(count: ((string | undefined) | undefined)) + @Provide({alias:"count",allowOverride:false}) set count(count: ((string | undefined) | undefined)) - get count(): ((string | undefined) | undefined) + @Provide({alias:"count",allowOverride:false}) get count(): ((string | undefined) | undefined) set __backing_count(__backing_count: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count1(count1: ((string | undefined) | undefined)) + @Provide({alias:"prov1",allowOverride:false}) set count1(count1: ((string | undefined) | undefined)) - get count1(): ((string | undefined) | undefined) + @Provide({alias:"prov1",allowOverride:false}) get count1(): ((string | undefined) | undefined) set __backing_count1(__backing_count1: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count1(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count2(count2: ((string | undefined) | undefined)) + @Provide({alias:"prov2",allowOverride:false}) set count2(count2: ((string | undefined) | undefined)) - get count2(): ((string | undefined) | undefined) + @Provide({alias:"prov2",allowOverride:false}) get count2(): ((string | undefined) | undefined) set __backing_count2(__backing_count2: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count2(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count3(count3: ((string | undefined) | undefined)) + @Provide({alias:"prov3",allowOverride:true}) set count3(count3: ((string | undefined) | undefined)) - get count3(): ((string | undefined) | undefined) + @Provide({alias:"prov3",allowOverride:true}) get count3(): ((string | undefined) | undefined) set __backing_count3(__backing_count3: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count3(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count4(count4: ((string | undefined) | undefined)) + @Provide({allowOverride:false,alias:"count4"}) set count4(count4: ((string | undefined) | undefined)) - get count4(): ((string | undefined) | undefined) + @Provide({allowOverride:false,alias:"count4"}) get count4(): ((string | undefined) | undefined) set __backing_count4(__backing_count4: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count4(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count5(count5: ((string | undefined) | undefined)) + @Provide({allowOverride:true,alias:"count5"}) set count5(count5: ((string | undefined) | undefined)) - get count5(): ((string | undefined) | undefined) + @Provide({allowOverride:true,alias:"count5"}) get count5(): ((string | undefined) | undefined) set __backing_count5(__backing_count5: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count5(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count6(count6: ((string | undefined) | undefined)) + @Provide({alias:"",allowOverride:true}) set count6(count6: ((string | undefined) | undefined)) - get count6(): ((string | undefined) | undefined) + @Provide({alias:"",allowOverride:true}) get count6(): ((string | undefined) | undefined) set __backing_count6(__backing_count6: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count6(): (IProvideDecoratedVariable<(string | undefined)> | undefined) - set count7(count7: ((string | undefined) | undefined)) + @Provide({alias:"",allowOverride:false}) set count7(count7: ((string | undefined) | undefined)) - get count7(): ((string | undefined) | undefined) + @Provide({alias:"",allowOverride:false}) get count7(): ((string | undefined) | undefined) set __backing_count7(__backing_count7: (IProvideDecoratedVariable<(string | undefined)> | undefined)) get __backing_count7(): (IProvideDecoratedVariable<(string | undefined)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts index 30f9174a5..73a4f2705 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts @@ -126,33 +126,33 @@ function main() {} } @Component() export interface __Options_PropParent { - set provideVar1(provideVar1: (string | undefined)) + @Provide({alias:"provideVar1",allowOverride:false}) set provideVar1(provideVar1: (string | undefined)) - get provideVar1(): (string | undefined) + @Provide({alias:"provideVar1",allowOverride:false}) get provideVar1(): (string | undefined) set __backing_provideVar1(__backing_provideVar1: (IProvideDecoratedVariable | undefined)) get __backing_provideVar1(): (IProvideDecoratedVariable | undefined) - set provideVar2(provideVar2: (number | undefined)) + @Provide({alias:"provideVar2",allowOverride:false}) set provideVar2(provideVar2: (number | undefined)) - get provideVar2(): (number | undefined) + @Provide({alias:"provideVar2",allowOverride:false}) get provideVar2(): (number | undefined) set __backing_provideVar2(__backing_provideVar2: (IProvideDecoratedVariable | undefined)) get __backing_provideVar2(): (IProvideDecoratedVariable | undefined) - set provideVar3(provideVar3: (boolean | undefined)) + @Provide({alias:"provideVar3",allowOverride:false}) set provideVar3(provideVar3: (boolean | undefined)) - get provideVar3(): (boolean | undefined) + @Provide({alias:"provideVar3",allowOverride:false}) get provideVar3(): (boolean | undefined) set __backing_provideVar3(__backing_provideVar3: (IProvideDecoratedVariable | undefined)) get __backing_provideVar3(): (IProvideDecoratedVariable | undefined) - set provideVar4(provideVar4: (undefined | undefined)) + @Provide({alias:"provideVar4",allowOverride:false}) set provideVar4(provideVar4: (undefined | undefined)) - get provideVar4(): (undefined | undefined) + @Provide({alias:"provideVar4",allowOverride:false}) get provideVar4(): (undefined | undefined) set __backing_provideVar4(__backing_provideVar4: (IProvideDecoratedVariable | undefined)) get __backing_provideVar4(): (IProvideDecoratedVariable | undefined) - set provideVar5(provideVar5: (null | undefined)) + @Provide({alias:"provideVar5",allowOverride:false}) set provideVar5(provideVar5: (null | undefined)) - get provideVar5(): (null | undefined) + @Provide({alias:"provideVar5",allowOverride:false}) get provideVar5(): (null | undefined) set __backing_provideVar5(__backing_provideVar5: (IProvideDecoratedVariable | undefined)) get __backing_provideVar5(): (IProvideDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts index a58210c09..689aaad40 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts @@ -287,75 +287,75 @@ final class PropType extends BaseEnum { } @Component() export interface __Options_Parent { - set provideVar1(provideVar1: (Per | undefined)) + @Provide({alias:"provideVar1",allowOverride:false}) set provideVar1(provideVar1: (Per | undefined)) - get provideVar1(): (Per | undefined) + @Provide({alias:"provideVar1",allowOverride:false}) get provideVar1(): (Per | undefined) set __backing_provideVar1(__backing_provideVar1: (IProvideDecoratedVariable | undefined)) get __backing_provideVar1(): (IProvideDecoratedVariable | undefined) - set provideVar2(provideVar2: (Array | undefined)) + @Provide({alias:"provideVar2",allowOverride:false}) set provideVar2(provideVar2: (Array | undefined)) - get provideVar2(): (Array | undefined) + @Provide({alias:"provideVar2",allowOverride:false}) get provideVar2(): (Array | undefined) set __backing_provideVar2(__backing_provideVar2: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar2(): (IProvideDecoratedVariable> | undefined) - set provideVar3(provideVar3: (PropType | undefined)) + @Provide({alias:"provideVar3",allowOverride:false}) set provideVar3(provideVar3: (PropType | undefined)) - get provideVar3(): (PropType | undefined) + @Provide({alias:"provideVar3",allowOverride:false}) get provideVar3(): (PropType | undefined) set __backing_provideVar3(__backing_provideVar3: (IProvideDecoratedVariable | undefined)) get __backing_provideVar3(): (IProvideDecoratedVariable | undefined) - set provideVar4(provideVar4: (Set | undefined)) + @Provide({alias:"provideVar4",allowOverride:false}) set provideVar4(provideVar4: (Set | undefined)) - get provideVar4(): (Set | undefined) + @Provide({alias:"provideVar4",allowOverride:false}) get provideVar4(): (Set | undefined) set __backing_provideVar4(__backing_provideVar4: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar4(): (IProvideDecoratedVariable> | undefined) - set provideVar5(provideVar5: (Array | undefined)) + @Provide({alias:"provideVar5",allowOverride:false}) set provideVar5(provideVar5: (Array | undefined)) - get provideVar5(): (Array | undefined) + @Provide({alias:"provideVar5",allowOverride:false}) get provideVar5(): (Array | undefined) set __backing_provideVar5(__backing_provideVar5: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar5(): (IProvideDecoratedVariable> | undefined) - set provideVar6(provideVar6: (Array | undefined)) + @Provide({alias:"provideVar6",allowOverride:false}) set provideVar6(provideVar6: (Array | undefined)) - get provideVar6(): (Array | undefined) + @Provide({alias:"provideVar6",allowOverride:false}) get provideVar6(): (Array | undefined) set __backing_provideVar6(__backing_provideVar6: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar6(): (IProvideDecoratedVariable> | undefined) - set provideVar7(provideVar7: (Array | undefined)) + @Provide({alias:"provideVar7",allowOverride:false}) set provideVar7(provideVar7: (Array | undefined)) - get provideVar7(): (Array | undefined) + @Provide({alias:"provideVar7",allowOverride:false}) get provideVar7(): (Array | undefined) set __backing_provideVar7(__backing_provideVar7: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar7(): (IProvideDecoratedVariable> | undefined) - set provideVar8(provideVar8: (((sr: string)=> void) | undefined)) + @Provide({alias:"provideVar8",allowOverride:false}) set provideVar8(provideVar8: (((sr: string)=> void) | undefined)) - get provideVar8(): (((sr: string)=> void) | undefined) + @Provide({alias:"provideVar8",allowOverride:false}) get provideVar8(): (((sr: string)=> void) | undefined) set __backing_provideVar8(__backing_provideVar8: (IProvideDecoratedVariable<((sr: string)=> void)> | undefined)) get __backing_provideVar8(): (IProvideDecoratedVariable<((sr: string)=> void)> | undefined) - set provideVar9(provideVar9: (Date | undefined)) + @Provide({alias:"provideVar9",allowOverride:false}) set provideVar9(provideVar9: (Date | undefined)) - get provideVar9(): (Date | undefined) + @Provide({alias:"provideVar9",allowOverride:false}) get provideVar9(): (Date | undefined) set __backing_provideVar9(__backing_provideVar9: (IProvideDecoratedVariable | undefined)) get __backing_provideVar9(): (IProvideDecoratedVariable | undefined) - set provideVar10(provideVar10: (Map | undefined)) + @Provide({alias:"provideVar10",allowOverride:false}) set provideVar10(provideVar10: (Map | undefined)) - get provideVar10(): (Map | undefined) + @Provide({alias:"provideVar10",allowOverride:false}) get provideVar10(): (Map | undefined) set __backing_provideVar10(__backing_provideVar10: (IProvideDecoratedVariable> | undefined)) get __backing_provideVar10(): (IProvideDecoratedVariable> | undefined) - set provideVar11(provideVar11: ((string | number) | undefined)) + @Provide({alias:"provideVar11",allowOverride:false}) set provideVar11(provideVar11: ((string | number) | undefined)) - get provideVar11(): ((string | number) | undefined) + @Provide({alias:"provideVar11",allowOverride:false}) get provideVar11(): ((string | number) | undefined) set __backing_provideVar11(__backing_provideVar11: (IProvideDecoratedVariable<(string | number)> | undefined)) get __backing_provideVar11(): (IProvideDecoratedVariable<(string | number)> | undefined) - set provideVar12(provideVar12: ((Set | Per) | undefined)) + @Provide({alias:"provideVar12",allowOverride:false}) set provideVar12(provideVar12: ((Set | Per) | undefined)) - get provideVar12(): ((Set | Per) | undefined) + @Provide({alias:"provideVar12",allowOverride:false}) get provideVar12(): ((Set | Per) | undefined) set __backing_provideVar12(__backing_provideVar12: (IProvideDecoratedVariable<(Set | Per)> | undefined)) get __backing_provideVar12(): (IProvideDecoratedVariable<(Set | Per)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index 6b65444af..94b38b10b 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -128,15 +128,15 @@ function main() {} } @Component() @Reusable() export interface __Options_Child { - set num(num: (number | undefined)) + @Prop() set num(num: (number | undefined)) - get num(): (number | undefined) + @Prop() get num(): (number | undefined) set __backing_num(__backing_num: (IPropDecoratedVariable | undefined)) get __backing_num(): (IPropDecoratedVariable | undefined) - set num1(num1: (number | undefined)) + @State() set num1(num1: (number | undefined)) - get num1(): (number | undefined) + @State() get num1(): (number | undefined) set __backing_num1(__backing_num1: (IStateDecoratedVariable | undefined)) get __backing_num1(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts index f741b2dea..a4258e596 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts @@ -180,9 +180,9 @@ class Message { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Index { - set display(display: (boolean | undefined)) + @State() set display(display: (boolean | undefined)) - get display(): (boolean | undefined) + @State() get display(): (boolean | undefined) set __backing_display(__backing_display: (IStateDecoratedVariable | undefined)) get __backing_display(): (IStateDecoratedVariable | undefined) @@ -190,9 +190,9 @@ class Message { } @Reusable() @Component() export interface __Options_Child { - set message(message: (Message | undefined)) + @State() set message(message: (Message | undefined)) - get message(): (Message | undefined) + @State() get message(): (Message | undefined) set __backing_message(__backing_message: (IStateDecoratedVariable | undefined)) get __backing_message(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts index 61b13a9fa..a9f88d4e3 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts @@ -129,33 +129,33 @@ function main() {} } @Component() export interface __Options_Parent { - set stateVar1(stateVar1: (string | undefined)) + @State() set stateVar1(stateVar1: (string | undefined)) - get stateVar1(): (string | undefined) + @State() get stateVar1(): (string | undefined) set __backing_stateVar1(__backing_stateVar1: (IStateDecoratedVariable | undefined)) get __backing_stateVar1(): (IStateDecoratedVariable | undefined) - set stateVar2(stateVar2: (number | undefined)) + @State() set stateVar2(stateVar2: (number | undefined)) - get stateVar2(): (number | undefined) + @State() get stateVar2(): (number | undefined) set __backing_stateVar2(__backing_stateVar2: (IStateDecoratedVariable | undefined)) get __backing_stateVar2(): (IStateDecoratedVariable | undefined) - set stateVar3(stateVar3: (boolean | undefined)) + @State() set stateVar3(stateVar3: (boolean | undefined)) - get stateVar3(): (boolean | undefined) + @State() get stateVar3(): (boolean | undefined) set __backing_stateVar3(__backing_stateVar3: (IStateDecoratedVariable | undefined)) get __backing_stateVar3(): (IStateDecoratedVariable | undefined) - set stateVar4(stateVar4: (undefined | undefined)) + @State() set stateVar4(stateVar4: (undefined | undefined)) - get stateVar4(): (undefined | undefined) + @State() get stateVar4(): (undefined | undefined) set __backing_stateVar4(__backing_stateVar4: (IStateDecoratedVariable | undefined)) get __backing_stateVar4(): (IStateDecoratedVariable | undefined) - set stateVar5(stateVar5: (null | undefined)) + @State() set stateVar5(stateVar5: (null | undefined)) - get stateVar5(): (null | undefined) + @State() get stateVar5(): (null | undefined) set __backing_stateVar5(__backing_stateVar5: (IStateDecoratedVariable | undefined)) get __backing_stateVar5(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts index d53dcb99e..9049e6859 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts @@ -287,75 +287,75 @@ final class StateType extends BaseEnum { } @Component() export interface __Options_Parent { - set stateVar1(stateVar1: (Per | undefined)) + @State() set stateVar1(stateVar1: (Per | undefined)) - get stateVar1(): (Per | undefined) + @State() get stateVar1(): (Per | undefined) set __backing_stateVar1(__backing_stateVar1: (IStateDecoratedVariable | undefined)) get __backing_stateVar1(): (IStateDecoratedVariable | undefined) - set stateVar2(stateVar2: (Array | undefined)) + @State() set stateVar2(stateVar2: (Array | undefined)) - get stateVar2(): (Array | undefined) + @State() get stateVar2(): (Array | undefined) set __backing_stateVar2(__backing_stateVar2: (IStateDecoratedVariable> | undefined)) get __backing_stateVar2(): (IStateDecoratedVariable> | undefined) - set stateVar3(stateVar3: (StateType | undefined)) + @State() set stateVar3(stateVar3: (StateType | undefined)) - get stateVar3(): (StateType | undefined) + @State() get stateVar3(): (StateType | undefined) set __backing_stateVar3(__backing_stateVar3: (IStateDecoratedVariable | undefined)) get __backing_stateVar3(): (IStateDecoratedVariable | undefined) - set stateVar4(stateVar4: (Set | undefined)) + @State() set stateVar4(stateVar4: (Set | undefined)) - get stateVar4(): (Set | undefined) + @State() get stateVar4(): (Set | undefined) set __backing_stateVar4(__backing_stateVar4: (IStateDecoratedVariable> | undefined)) get __backing_stateVar4(): (IStateDecoratedVariable> | undefined) - set stateVar5(stateVar5: (Array | undefined)) + @State() set stateVar5(stateVar5: (Array | undefined)) - get stateVar5(): (Array | undefined) + @State() get stateVar5(): (Array | undefined) set __backing_stateVar5(__backing_stateVar5: (IStateDecoratedVariable> | undefined)) get __backing_stateVar5(): (IStateDecoratedVariable> | undefined) - set stateVar6(stateVar6: (Array | undefined)) + @State() set stateVar6(stateVar6: (Array | undefined)) - get stateVar6(): (Array | undefined) + @State() get stateVar6(): (Array | undefined) set __backing_stateVar6(__backing_stateVar6: (IStateDecoratedVariable> | undefined)) get __backing_stateVar6(): (IStateDecoratedVariable> | undefined) - set stateVar7(stateVar7: (Array | undefined)) + @State() set stateVar7(stateVar7: (Array | undefined)) - get stateVar7(): (Array | undefined) + @State() get stateVar7(): (Array | undefined) set __backing_stateVar7(__backing_stateVar7: (IStateDecoratedVariable> | undefined)) get __backing_stateVar7(): (IStateDecoratedVariable> | undefined) - set stateVar8(stateVar8: (((sr: string)=> void) | undefined)) + @State() set stateVar8(stateVar8: (((sr: string)=> void) | undefined)) - get stateVar8(): (((sr: string)=> void) | undefined) + @State() get stateVar8(): (((sr: string)=> void) | undefined) set __backing_stateVar8(__backing_stateVar8: (IStateDecoratedVariable<((sr: string)=> void)> | undefined)) get __backing_stateVar8(): (IStateDecoratedVariable<((sr: string)=> void)> | undefined) - set stateVar9(stateVar9: (Date | undefined)) + @State() set stateVar9(stateVar9: (Date | undefined)) - get stateVar9(): (Date | undefined) + @State() get stateVar9(): (Date | undefined) set __backing_stateVar9(__backing_stateVar9: (IStateDecoratedVariable | undefined)) get __backing_stateVar9(): (IStateDecoratedVariable | undefined) - set stateVar10(stateVar10: (Map | undefined)) + @State() set stateVar10(stateVar10: (Map | undefined)) - get stateVar10(): (Map | undefined) + @State() get stateVar10(): (Map | undefined) set __backing_stateVar10(__backing_stateVar10: (IStateDecoratedVariable> | undefined)) get __backing_stateVar10(): (IStateDecoratedVariable> | undefined) - set stateVar11(stateVar11: ((string | number) | undefined)) + @State() set stateVar11(stateVar11: ((string | number) | undefined)) - get stateVar11(): ((string | number) | undefined) + @State() get stateVar11(): ((string | number) | undefined) set __backing_stateVar11(__backing_stateVar11: (IStateDecoratedVariable<(string | number)> | undefined)) get __backing_stateVar11(): (IStateDecoratedVariable<(string | number)> | undefined) - set stateVar12(stateVar12: ((Set | Per) | undefined)) + @State() set stateVar12(stateVar12: ((Set | Per) | undefined)) - get stateVar12(): ((Set | Per) | undefined) + @State() get stateVar12(): ((Set | Per) | undefined) set __backing_stateVar12(__backing_stateVar12: (IStateDecoratedVariable<(Set | Per)> | undefined)) get __backing_stateVar12(): (IStateDecoratedVariable<(Set | Per)> | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts index 09310a680..a1fa5fd87 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts @@ -124,9 +124,9 @@ class Per { } @Component() export interface __Options_Parent { - set parentVar1(parentVar1: (Per | undefined)) + @State() set parentVar1(parentVar1: (Per | undefined)) - get parentVar1(): (Per | undefined) + @State() get parentVar1(): (Per | undefined) set __backing_parentVar1(__backing_parentVar1: (IStateDecoratedVariable | undefined)) get __backing_parentVar1(): (IStateDecoratedVariable | undefined) @@ -134,9 +134,9 @@ class Per { } @Component() export interface __Options_Child { - set childVar1(childVar1: (Per | undefined)) + @State() set childVar1(childVar1: (Per | undefined)) - get childVar1(): (Per | undefined) + @State() get childVar1(): (Per | undefined) set __backing_childVar1(__backing_childVar1: (IStateDecoratedVariable | undefined)) get __backing_childVar1(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts index 8216a6a04..e32943ac7 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts @@ -119,15 +119,15 @@ class Data { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Index { - set storageLink(storageLink: (number | undefined)) + @StorageLink({value:"PropA"}) set storageLink(storageLink: (number | undefined)) - get storageLink(): (number | undefined) + @StorageLink({value:"PropA"}) get storageLink(): (number | undefined) set __backing_storageLink(__backing_storageLink: (IStorageLinkDecoratedVariable | undefined)) get __backing_storageLink(): (IStorageLinkDecoratedVariable | undefined) - set storageLinkObject(storageLinkObject: (Data | undefined)) + @StorageLink({value:"PropB"}) set storageLinkObject(storageLinkObject: (Data | undefined)) - get storageLinkObject(): (Data | undefined) + @StorageLink({value:"PropB"}) get storageLinkObject(): (Data | undefined) set __backing_storageLinkObject(__backing_storageLinkObject: (IStorageLinkDecoratedVariable | undefined)) get __backing_storageLinkObject(): (IStorageLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts index dfed251b2..21540b68f 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts @@ -223,45 +223,45 @@ final class Status extends BaseEnum { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set arrayA(arrayA: (Array | undefined)) + @StorageLink({value:"Prop1"}) set arrayA(arrayA: (Array | undefined)) - get arrayA(): (Array | undefined) + @StorageLink({value:"Prop1"}) get arrayA(): (Array | undefined) set __backing_arrayA(__backing_arrayA: (IStorageLinkDecoratedVariable> | undefined)) get __backing_arrayA(): (IStorageLinkDecoratedVariable> | undefined) - set objectA(objectA: (Object | undefined)) + @StorageLink({value:"Prop2"}) set objectA(objectA: (Object | undefined)) - get objectA(): (Object | undefined) + @StorageLink({value:"Prop2"}) get objectA(): (Object | undefined) set __backing_objectA(__backing_objectA: (IStorageLinkDecoratedVariable | undefined)) get __backing_objectA(): (IStorageLinkDecoratedVariable | undefined) - set dateA(dateA: (Date | undefined)) + @StorageLink({value:"Prop3"}) set dateA(dateA: (Date | undefined)) - get dateA(): (Date | undefined) + @StorageLink({value:"Prop3"}) get dateA(): (Date | undefined) set __backing_dateA(__backing_dateA: (IStorageLinkDecoratedVariable | undefined)) get __backing_dateA(): (IStorageLinkDecoratedVariable | undefined) - set setA(setA: (Set | undefined)) + @StorageLink({value:"Prop4"}) set setA(setA: (Set | undefined)) - get setA(): (Set | undefined) + @StorageLink({value:"Prop4"}) get setA(): (Set | undefined) set __backing_setA(__backing_setA: (IStorageLinkDecoratedVariable> | undefined)) get __backing_setA(): (IStorageLinkDecoratedVariable> | undefined) - set mapA(mapA: (Map | undefined)) + @StorageLink({value:"Prop5"}) set mapA(mapA: (Map | undefined)) - get mapA(): (Map | undefined) + @StorageLink({value:"Prop5"}) get mapA(): (Map | undefined) set __backing_mapA(__backing_mapA: (IStorageLinkDecoratedVariable> | undefined)) get __backing_mapA(): (IStorageLinkDecoratedVariable> | undefined) - set classA(classA: (Person | undefined)) + @StorageLink({value:"Prop7"}) set classA(classA: (Person | undefined)) - get classA(): (Person | undefined) + @StorageLink({value:"Prop7"}) get classA(): (Person | undefined) set __backing_classA(__backing_classA: (IStorageLinkDecoratedVariable | undefined)) get __backing_classA(): (IStorageLinkDecoratedVariable | undefined) - set enumA(enumA: (Status | undefined)) + @StorageLink({value:"Prop8"}) set enumA(enumA: (Status | undefined)) - get enumA(): (Status | undefined) + @StorageLink({value:"Prop8"}) get enumA(): (Status | undefined) set __backing_enumA(__backing_enumA: (IStorageLinkDecoratedVariable | undefined)) get __backing_enumA(): (IStorageLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts index 2b544b794..ac9261e4a 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts @@ -104,21 +104,21 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set numA(numA: (number | undefined)) + @StorageLink({value:"Prop1"}) set numA(numA: (number | undefined)) - get numA(): (number | undefined) + @StorageLink({value:"Prop1"}) get numA(): (number | undefined) set __backing_numA(__backing_numA: (IStorageLinkDecoratedVariable | undefined)) get __backing_numA(): (IStorageLinkDecoratedVariable | undefined) - set stringA(stringA: (string | undefined)) + @StorageLink({value:"Prop2"}) set stringA(stringA: (string | undefined)) - get stringA(): (string | undefined) + @StorageLink({value:"Prop2"}) get stringA(): (string | undefined) set __backing_stringA(__backing_stringA: (IStorageLinkDecoratedVariable | undefined)) get __backing_stringA(): (IStorageLinkDecoratedVariable | undefined) - set booleanA(booleanA: (boolean | undefined)) + @StorageLink({value:"Prop3"}) set booleanA(booleanA: (boolean | undefined)) - get booleanA(): (boolean | undefined) + @StorageLink({value:"Prop3"}) get booleanA(): (boolean | undefined) set __backing_booleanA(__backing_booleanA: (IStorageLinkDecoratedVariable | undefined)) get __backing_booleanA(): (IStorageLinkDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts index 60263a471..686d5a312 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts @@ -219,45 +219,45 @@ final class Status extends BaseEnum { } @Component() export interface __Options_MyStateSample { - set arrayB(arrayB: (Array | undefined)) + @StoragePropRef({value:"Prop1"}) set arrayB(arrayB: (Array | undefined)) - get arrayB(): (Array | undefined) + @StoragePropRef({value:"Prop1"}) get arrayB(): (Array | undefined) set __backing_arrayB(__backing_arrayB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_arrayB(): (IStoragePropRefDecoratedVariable> | undefined) - set objectB(objectB: (Object | undefined)) + @StoragePropRef({value:"Prop2"}) set objectB(objectB: (Object | undefined)) - get objectB(): (Object | undefined) + @StoragePropRef({value:"Prop2"}) get objectB(): (Object | undefined) set __backing_objectB(__backing_objectB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_objectB(): (IStoragePropRefDecoratedVariable | undefined) - set dateB(dateB: (Date | undefined)) + @StoragePropRef({value:"Prop3"}) set dateB(dateB: (Date | undefined)) - get dateB(): (Date | undefined) + @StoragePropRef({value:"Prop3"}) get dateB(): (Date | undefined) set __backing_dateB(__backing_dateB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_dateB(): (IStoragePropRefDecoratedVariable | undefined) - set setB(setB: (Set | undefined)) + @StoragePropRef({value:"Prop4"}) set setB(setB: (Set | undefined)) - get setB(): (Set | undefined) + @StoragePropRef({value:"Prop4"}) get setB(): (Set | undefined) set __backing_setB(__backing_setB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_setB(): (IStoragePropRefDecoratedVariable> | undefined) - set mapB(mapB: (Map | undefined)) + @StoragePropRef({value:"Prop5"}) set mapB(mapB: (Map | undefined)) - get mapB(): (Map | undefined) + @StoragePropRef({value:"Prop5"}) get mapB(): (Map | undefined) set __backing_mapB(__backing_mapB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_mapB(): (IStoragePropRefDecoratedVariable> | undefined) - set classB(classB: (Person | undefined)) + @StoragePropRef({value:"Prop7"}) set classB(classB: (Person | undefined)) - get classB(): (Person | undefined) + @StoragePropRef({value:"Prop7"}) get classB(): (Person | undefined) set __backing_classB(__backing_classB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_classB(): (IStoragePropRefDecoratedVariable | undefined) - set enumB(enumB: (Status | undefined)) + @StoragePropRef({value:"Prop8"}) set enumB(enumB: (Status | undefined)) - get enumB(): (Status | undefined) + @StoragePropRef({value:"Prop8"}) get enumB(): (Status | undefined) set __backing_enumB(__backing_enumB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_enumB(): (IStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts index cbf9c9f85..d12716606 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts @@ -122,33 +122,33 @@ function main() {} } @Component() export interface __Options_MyStateSample { - set numB(numB: (number | undefined)) + @StoragePropRef({value:"Prop1"}) set numB(numB: (number | undefined)) - get numB(): (number | undefined) + @StoragePropRef({value:"Prop1"}) get numB(): (number | undefined) set __backing_numB(__backing_numB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_numB(): (IStoragePropRefDecoratedVariable | undefined) - set stringB(stringB: (string | undefined)) + @StoragePropRef({value:"Prop2"}) set stringB(stringB: (string | undefined)) - get stringB(): (string | undefined) + @StoragePropRef({value:"Prop2"}) get stringB(): (string | undefined) set __backing_stringB(__backing_stringB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_stringB(): (IStoragePropRefDecoratedVariable | undefined) - set booleanB(booleanB: (boolean | undefined)) + @StoragePropRef({value:"Prop3"}) set booleanB(booleanB: (boolean | undefined)) - get booleanB(): (boolean | undefined) + @StoragePropRef({value:"Prop3"}) get booleanB(): (boolean | undefined) set __backing_booleanB(__backing_booleanB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_booleanB(): (IStoragePropRefDecoratedVariable | undefined) - set undefinedB(undefinedB: (undefined | undefined)) + @StoragePropRef({value:"Prop4"}) set undefinedB(undefinedB: (undefined | undefined)) - get undefinedB(): (undefined | undefined) + @StoragePropRef({value:"Prop4"}) get undefinedB(): (undefined | undefined) set __backing_undefinedB(__backing_undefinedB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_undefinedB(): (IStoragePropRefDecoratedVariable | undefined) - set nullB(nullB: (null | undefined)) + @StoragePropRef({value:"Prop5"}) set nullB(nullB: (null | undefined)) - get nullB(): (null | undefined) + @StoragePropRef({value:"Prop5"}) get nullB(): (null | undefined) set __backing_nullB(__backing_nullB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_nullB(): (IStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts index 6c3476c96..68c7b42c2 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts @@ -131,15 +131,15 @@ class Data { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Index { - set storageProp(storageProp: (number | undefined)) + @StorageProp({value:"PropA"}) set storageProp(storageProp: (number | undefined)) - get storageProp(): (number | undefined) + @StorageProp({value:"PropA"}) get storageProp(): (number | undefined) set __backing_storageProp(__backing_storageProp: (IStoragePropRefDecoratedVariable | undefined)) get __backing_storageProp(): (IStoragePropRefDecoratedVariable | undefined) - set storagePropObject(storagePropObject: (Data | undefined)) + @StorageProp({value:"PropB"}) set storagePropObject(storagePropObject: (Data | undefined)) - get storagePropObject(): (Data | undefined) + @StorageProp({value:"PropB"}) get storagePropObject(): (Data | undefined) set __backing_storagePropObject(__backing_storagePropObject: (IStoragePropRefDecoratedVariable | undefined)) get __backing_storagePropObject(): (IStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts index e03a903c5..6d3d44d76 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts @@ -223,45 +223,45 @@ final class Status extends BaseEnum { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set arrayB(arrayB: (Array | undefined)) + @StorageProp({value:"Prop1"}) set arrayB(arrayB: (Array | undefined)) - get arrayB(): (Array | undefined) + @StorageProp({value:"Prop1"}) get arrayB(): (Array | undefined) set __backing_arrayB(__backing_arrayB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_arrayB(): (IStoragePropRefDecoratedVariable> | undefined) - set objectB(objectB: (Object | undefined)) + @StorageProp({value:"Prop2"}) set objectB(objectB: (Object | undefined)) - get objectB(): (Object | undefined) + @StorageProp({value:"Prop2"}) get objectB(): (Object | undefined) set __backing_objectB(__backing_objectB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_objectB(): (IStoragePropRefDecoratedVariable | undefined) - set dateB(dateB: (Date | undefined)) + @StorageProp({value:"Prop3"}) set dateB(dateB: (Date | undefined)) - get dateB(): (Date | undefined) + @StorageProp({value:"Prop3"}) get dateB(): (Date | undefined) set __backing_dateB(__backing_dateB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_dateB(): (IStoragePropRefDecoratedVariable | undefined) - set setB(setB: (Set | undefined)) + @StorageProp({value:"Prop4"}) set setB(setB: (Set | undefined)) - get setB(): (Set | undefined) + @StorageProp({value:"Prop4"}) get setB(): (Set | undefined) set __backing_setB(__backing_setB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_setB(): (IStoragePropRefDecoratedVariable> | undefined) - set mapB(mapB: (Map | undefined)) + @StorageProp({value:"Prop5"}) set mapB(mapB: (Map | undefined)) - get mapB(): (Map | undefined) + @StorageProp({value:"Prop5"}) get mapB(): (Map | undefined) set __backing_mapB(__backing_mapB: (IStoragePropRefDecoratedVariable> | undefined)) get __backing_mapB(): (IStoragePropRefDecoratedVariable> | undefined) - set classB(classB: (Person | undefined)) + @StorageProp({value:"Prop7"}) set classB(classB: (Person | undefined)) - get classB(): (Person | undefined) + @StorageProp({value:"Prop7"}) get classB(): (Person | undefined) set __backing_classB(__backing_classB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_classB(): (IStoragePropRefDecoratedVariable | undefined) - set enumB(enumB: (Status | undefined)) + @StorageProp({value:"Prop8"}) set enumB(enumB: (Status | undefined)) - get enumB(): (Status | undefined) + @StorageProp({value:"Prop8"}) get enumB(): (Status | undefined) set __backing_enumB(__backing_enumB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_enumB(): (IStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts index 25ed76fde..0592f34c1 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts @@ -113,21 +113,21 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set numB(numB: (number | undefined)) + @StorageProp({value:"Prop1"}) set numB(numB: (number | undefined)) - get numB(): (number | undefined) + @StorageProp({value:"Prop1"}) get numB(): (number | undefined) set __backing_numB(__backing_numB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_numB(): (IStoragePropRefDecoratedVariable | undefined) - set stringB(stringB: (string | undefined)) + @StorageProp({value:"Prop2"}) set stringB(stringB: (string | undefined)) - get stringB(): (string | undefined) + @StorageProp({value:"Prop2"}) get stringB(): (string | undefined) set __backing_stringB(__backing_stringB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_stringB(): (IStoragePropRefDecoratedVariable | undefined) - set booleanB(booleanB: (boolean | undefined)) + @StorageProp({value:"Prop3"}) set booleanB(booleanB: (boolean | undefined)) - get booleanB(): (boolean | undefined) + @StorageProp({value:"Prop3"}) get booleanB(): (boolean | undefined) set __backing_booleanB(__backing_booleanB: (IStoragePropRefDecoratedVariable | undefined)) get __backing_booleanB(): (IStoragePropRefDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts index ecff9abbc..5f7dcf0e9 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts @@ -307,48 +307,46 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set statevar(statevar: (string | undefined)) + @State() @Watch({value:"stateOnChange"}) set statevar(statevar: (string | undefined)) - get statevar(): (string | undefined) + @State() @Watch({value:"stateOnChange"}) get statevar(): (string | undefined) set __backing_statevar(__backing_statevar: (IStateDecoratedVariable | undefined)) get __backing_statevar(): (IStateDecoratedVariable | undefined) - set propvar(propvar: (string | undefined)) + @Prop() @Watch({value:"propOnChange"}) set propvar(propvar: (string | undefined)) - get propvar(): (string | undefined) + @Prop() @Watch({value:"propOnChange"}) get propvar(): (string | undefined) set __backing_propvar(__backing_propvar: (IPropDecoratedVariable | undefined)) get __backing_propvar(): (IPropDecoratedVariable | undefined) - @__Link_intrinsic() set linkvar(linkvar: (string | undefined)) + @Link() @Watch({value:"linkOnChange"}) set linkvar(linkvar: (string | undefined)) - @__Link_intrinsic() get linkvar(): (string | undefined) + @Link() @Watch({value:"linkOnChange"}) get linkvar(): (string | undefined) set __backing_linkvar(__backing_linkvar: (LinkSourceType | undefined)) get __backing_linkvar(): (LinkSourceType | undefined) - set storagelinkvar(storagelinkvar: (string | undefined)) + @StorageLink({value:"prop1"}) @Watch({value:"storageLinkOnChange"}) set storagelinkvar(storagelinkvar: (string | undefined)) - get storagelinkvar(): (string | undefined) + @StorageLink({value:"prop1"}) @Watch({value:"storageLinkOnChange"}) get storagelinkvar(): (string | undefined) set __backing_storagelinkvar(__backing_storagelinkvar: (IStorageLinkDecoratedVariable | undefined)) get __backing_storagelinkvar(): (IStorageLinkDecoratedVariable | undefined) - set storagepropvar(storagepropvar: (string | undefined)) + @StorageProp({value:"prop2"}) @Watch({value:"storagePropOnChange"}) set storagepropvar(storagepropvar: (string | undefined)) - get storagepropvar(): (string | undefined) + @StorageProp({value:"prop2"}) @Watch({value:"storagePropOnChange"}) get storagepropvar(): (string | undefined) set __backing_storagepropvar(__backing_storagepropvar: (IStoragePropRefDecoratedVariable | undefined)) get __backing_storagepropvar(): (IStoragePropRefDecoratedVariable | undefined) - set objectlinkvar(objectlinkvar: (A | undefined)) + @ObjectLink() @Watch({value:"objectLinkOnChange"}) set objectlinkvar(objectlinkvar: (A | undefined)) - get objectlinkvar(): (A | undefined) + @ObjectLink() @Watch({value:"objectLinkOnChange"}) get objectlinkvar(): (A | undefined) set __backing_objectlinkvar(__backing_objectlinkvar: (IObjectLinkDecoratedVariable | undefined)) get __backing_objectlinkvar(): (IObjectLinkDecoratedVariable | undefined) - set providevar(providevar: (string | undefined)) + @Provide({alias:"providevar",allowOverride:false}) @Watch({value:"ProvideOnChange"}) set providevar(providevar: (string | undefined)) - get providevar(): (string | undefined) + @Provide({alias:"providevar",allowOverride:false}) @Watch({value:"ProvideOnChange"}) get providevar(): (string | undefined) set __backing_providevar(__backing_providevar: (IProvideDecoratedVariable | undefined)) get __backing_providevar(): (IProvideDecoratedVariable | undefined) @@ -356,9 +354,9 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Component() export interface __Options_Child { - set providevar(providevar: (string | undefined)) + @Consume({alias:""}) @Watch({value:"ConsumeOnChange"}) set providevar(providevar: (string | undefined)) - get providevar(): (string | undefined) + @Consume({alias:""}) @Watch({value:"ConsumeOnChange"}) get providevar(): (string | undefined) set __backing_providevar(__backing_providevar: (IConsumeDecoratedVariable | undefined)) get __backing_providevar(): (IConsumeDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts index 216eb9086..74a425ebf 100644 --- a/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts @@ -126,9 +126,9 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - set boo(boo: (boolean | undefined)) + @State() set boo(boo: (boolean | undefined)) - get boo(): (boolean | undefined) + @State() get boo(): (boolean | undefined) set __backing_boo(__backing_boo: (IStateDecoratedVariable | undefined)) get __backing_boo(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts b/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts index 0147ea48f..1896e0256 100644 --- a/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts @@ -73,9 +73,9 @@ import hilog from "@ohos.hilog"; } @Entry() @Component() export interface __Options_A { - a?: string; + @State() a?: string; @State() __backing_a?: string; - b?: string; + @Prop() b?: string; @Prop() __backing_b?: string; } @@ -191,15 +191,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_A { - set a(a: (string | undefined)) + @State() set a(a: (string | undefined)) - get a(): (string | undefined) + @State() get a(): (string | undefined) set __backing_a(__backing_a: (IStateDecoratedVariable | undefined)) get __backing_a(): (IStateDecoratedVariable | undefined) - set b(b: (string | undefined)) + @Prop() set b(b: (string | undefined)) - get b(): (string | undefined) + @Prop() get b(): (string | undefined) set __backing_b(__backing_b: (IPropDecoratedVariable | undefined)) get __backing_b(): (IPropDecoratedVariable | undefined) diff --git a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts index 38ef976e6..28a031c9a 100644 --- a/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts @@ -168,9 +168,9 @@ function main() {} } @Component() export interface __Options_Parent { - set label(label: (Tmp | undefined)) + @State() set label(label: (Tmp | undefined)) - get label(): (Tmp | undefined) + @State() get label(): (Tmp | undefined) set __backing_label(__backing_label: (IStateDecoratedVariable | undefined)) get __backing_label(): (IStateDecoratedVariable | undefined) @@ -361,9 +361,9 @@ function main() {} } @Component() export interface __Options_Parent { - set label(label: (Tmp | undefined)) + @State() set label(label: (Tmp | undefined)) - get label(): (Tmp | undefined) + @State() get label(): (Tmp | undefined) set __backing_label(__backing_label: (IStateDecoratedVariable | undefined)) get __backing_label(): (IStateDecoratedVariable | undefined) diff --git a/arkui-plugins/test/utils/plugins/memo-no-recheck.ts b/arkui-plugins/test/utils/plugins/memo-no-recheck.ts index 9396b34e5..d3047d96c 100644 --- a/arkui-plugins/test/utils/plugins/memo-no-recheck.ts +++ b/arkui-plugins/test/utils/plugins/memo-no-recheck.ts @@ -16,7 +16,11 @@ import * as arkts from '@koalaui/libarkts'; import { PluginContext, Plugins } from '../../../common/plugin-context'; import { ProgramVisitor } from '../../../common/program-visitor'; -import { EXTERNAL_SOURCE_PREFIX_NAMES, EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK } from '../../../common/predefines'; +import { + EXTERNAL_SOURCE_PREFIX_NAMES, + EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK, + NodeCacheNames, +} from '../../../common/predefines'; import { PositionalIdTracker } from '../../../memo-plugins/utils'; import { ParameterTransformer } from '../../../memo-plugins/parameter-transformer'; import { ReturnTransformer } from '../../../memo-plugins/return-transformer'; @@ -51,7 +55,7 @@ export const memoNoRecheck: Plugins = { returnTransformer, signatureTransformer, internalsTransformer, - useCache: arkts.NodeCache.getInstance().isCollected() + useCache: arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).isCollected(), }); const skipPrefixNames = isFrameworkMode ? EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK @@ -64,7 +68,7 @@ export const memoNoRecheck: Plugins = { pluginContext: this, }); program = programVisitor.programVisitor(program); - arkts.NodeCache.getInstance().clear(); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).clear(); script = program.astNode; return script; } diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index 17af3f52a..397388895 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -14,9 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; -import { BuilderLambdaNames } from '../utils'; import { - backingField, filterDefined, isDecoratorAnnotation, removeAnnotationByName, @@ -49,16 +47,18 @@ import { BuilderLambdaConditionBranchInfo, BuilderLambdaChainingCallArgInfo, } from './utils'; -import { hasDecorator, isDecoratorIntrinsicAnnotation } from '../property-translators/utils'; +import { hasDecorator } from '../property-translators/utils'; import { factory as PropertyFactory } from '../property-translators/factory'; import { factory as UIFactory } from '../ui-factory'; +import { backingField, checkIsNameStartWithBackingField } from '../property-translators/utils'; import { AnimationNames, ARKUI_BUILDER_SOURCE_NAME, BindableDecl, ConditionNames, - DecoratorIntrinsicNames, + BuilderLambdaNames, DecoratorNames, + NodeCacheNames, } from '../../common/predefines'; import { ImportCollector } from '../../common/import-collector'; import { addMemoAnnotation, collectMemoableInfoInParameter } from '../../collectors/memo-collectors/utils'; @@ -218,7 +218,7 @@ export class factory { ); const returnStatement = arkts.factory.createReturnStatement(); - arkts.NodeCache.getInstance().collect(returnStatement); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(returnStatement); const body: arkts.BlockStatement = arkts.factory.createBlock([ arkts.factory.createExpressionStatement(lambdaBody), returnStatement, @@ -267,7 +267,7 @@ export class factory { arkts.factory.createIdentifier(BuilderLambdaNames.STYLE_PARAM_NAME, optionalFuncType), undefined ); - arkts.NodeCache.getInstance().collect(parameter); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(parameter); return parameter; } @@ -336,20 +336,21 @@ export class factory { } const returnType: arkts.TypeNode | undefined = decl.scriptFunction.returnTypeAnnotation; const isBindable: boolean = !!returnType && hasBindableProperty(returnType, BindableDecl.BINDABLE); + const isNotBacking: boolean = !checkIsNameStartWithBackingField(decl.name); let isBuilderParam: boolean = false; - let isLinkIntrinsic: boolean = false; + let isLink: boolean = false; decl.scriptFunction.annotations.forEach((anno) => { isBuilderParam ||= isDecoratorAnnotation(anno, DecoratorNames.BUILDER_PARAM); - isLinkIntrinsic ||= isDecoratorIntrinsicAnnotation(anno, DecoratorIntrinsicNames.LINK); + isLink ||= isDecoratorAnnotation(anno, DecoratorNames.LINK); }); - if (isBindable && isDoubleDollarCall(prop.value)) { return factory.updateBindableProperty(prop); - } else if (isBuilderParam && arkts.isArrowFunctionExpression(prop.value)) { + } else if (isBuilderParam && isNotBacking && arkts.isArrowFunctionExpression(prop.value)) { addMemoAnnotation(prop.value); return prop; } else if ( - isLinkIntrinsic && + isLink && + isNotBacking && arkts.isIdentifier(prop.key) && arkts.isMemberExpression(prop.value) && arkts.isThisExpression(prop.value.object) && @@ -533,7 +534,7 @@ export class factory { const newCall = arkts.factory.createCallExpression(arkts.factory.createIdentifier(condition), undefined, [ contentArg, ]); - arkts.NodeCache.getInstance().collect(newCall); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newCall); ImportCollector.getInstance().collectSource(condition, ARKUI_BUILDER_SOURCE_NAME); ImportCollector.getInstance().collectImport(condition); return arkts.factory.createExpressionStatement(newCall); @@ -611,7 +612,7 @@ export class factory { replaceBuilderLambdaDeclMethodName(node.name.name), externalSourceName ).setOverloads(newOverloads); - arkts.NodeCache.getInstance().collect(newNode); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); return newNode; } @@ -694,7 +695,7 @@ export class factory { instanceCalls = instanceCalls.reverse(); this.updateAnimation(instanceCalls); lambdaBody = arkts.factory.createIdentifier(BuilderLambdaNames.STYLE_ARROW_PARAM_NAME); - arkts.NodeCache.getInstance().collect(lambdaBody); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(lambdaBody); instanceCalls.forEach((callInfo) => { lambdaBody = this.createStyleLambdaBody(lambdaBody!, callInfo); }); @@ -702,7 +703,7 @@ export class factory { const args: (arkts.AstNode | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBody!, declInfo); const newNode = arkts.factory.updateCallExpression(node, replace, leaf.typeArguments, filterDefined(args)); - arkts.NodeCache.getInstance().collect(newNode); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); return newNode; } @@ -817,7 +818,7 @@ export class factory { undefined ); param.annotations = [annotation(DecoratorNames.BUILDER)]; - arkts.NodeCache.getInstance().collect(param); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(param); const method = UIFactory.createMethodDefinition({ key, kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_NONE, @@ -831,7 +832,7 @@ export class factory { }, modifiers, }); - arkts.NodeCache.getInstance().collect(method); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method); return method; } diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index 711dcfb4a..1b279d6f0 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -15,9 +15,15 @@ import * as arkts from '@koalaui/libarkts'; import { isAnnotation, matchPrefix } from '../../common/arkts-utils'; -import { BuilderLambdaNames, isCustomComponentAnnotation } from '../utils'; +import { isCustomComponentAnnotation } from '../utils'; import { DeclarationCollector } from '../../common/declaration-collector'; -import { ARKUI_IMPORT_PREFIX_NAMES, BindableDecl, Dollars, StructDecoratorNames } from '../../common/predefines'; +import { + ARKUI_IMPORT_PREFIX_NAMES, + BindableDecl, + BuilderLambdaNames, + Dollars, + StructDecoratorNames, +} from '../../common/predefines'; import { ImportCollector } from '../../common/import-collector'; export type BuilderLambdaDeclInfo = { @@ -319,7 +325,7 @@ export function findBuilderLambdaDecl(node: arkts.CallExpression | arkts.Identif if (!decl) { return undefined; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName) { return undefined; } @@ -347,7 +353,7 @@ export function findBuilderLambdaDeclInfo(decl: arkts.AstNode | undefined): Buil if (!decl) { return undefined; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName) { return undefined; } @@ -477,7 +483,7 @@ export function isDoubleDollarCall( if (!decl) { return false; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName)) { return false; } diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index 8fe41f30c..7302da391 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -32,18 +32,13 @@ import { LoaderJson, ResourceInfo, ScopeInfoCollection, - isForEachDecl + isForEachDecl, } from './struct-translators/utils'; -import { - collectCustomComponentScopeInfo, - CustomComponentNames, - CustomDialogNames, - isCustomComponentClass, - isSpecificNewClass, -} from './utils'; +import { collectCustomComponentScopeInfo, isCustomComponentClass, isSpecificNewClass } from './utils'; import { findAndCollectMemoableNode } from '../collectors/memo-collectors/factory'; import { InteroperAbilityNames } from './interop/predefines'; import { generateBuilderCompatible } from './interop/builder-interop'; +import { CustomComponentNames, CustomDialogNames } from '../common/predefines'; export class CheckedTransformer extends AbstractVisitor { private scope: ScopeInfoCollection; @@ -118,19 +113,18 @@ export class CheckedTransformer extends AbstractVisitor { if (!decl || this.legacyBuilderSet.size === 0) { return false; } - const moduleName = arkts.getProgramFromAstNode(decl).moduleName?.split('/')[0]; - - if (!this.legacyBuilderSet.has(moduleName)) { + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName?.split('/')[0]; + if (!moduleName || !this.legacyBuilderSet.has(moduleName)) { return false; } let isFrom1_1 = false; if (arkts.isMethodDefinition(decl)) { const annotations = decl.scriptFunction.annotations; - const decorators: string[] = annotations.map(annotation => { + const decorators: string[] = annotations.map((annotation) => { return (annotation.expr as arkts.Identifier).name; }); - decorators.forEach(element => { + decorators.forEach((element) => { if (element === 'Builder') { isFrom1_1 = true; return; @@ -192,7 +186,10 @@ export class CheckedTransformer extends AbstractVisitor { return structFactory.AddArrowTypeForParameter(node); } else if (arkts.isTSInterfaceDeclaration(node)) { return structFactory.tranformInterfaceMembers(node, this.externalSourceName); - } else if (arkts.isETSNewClassInstanceExpression(node) && isSpecificNewClass(node, CustomDialogNames.CUSTOM_DIALOG_CONTROLLER)) { + } else if ( + arkts.isETSNewClassInstanceExpression(node) && + isSpecificNewClass(node, CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) + ) { return structFactory.transformCustomDialogController(node); } diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index 83661d687..ede38a64b 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -19,7 +19,6 @@ const interop = require(getInteropPath()); const nullptr = interop.nullptr; import { AbstractVisitor, VisitorOptions } from '../common/abstract-visitor'; import { - CustomComponentNames, getCustomComponentOptionsName, findLocalImport, CustomComponentInfo, @@ -29,30 +28,22 @@ import { getComponentExtendsName, ComponentType, } from './utils'; -import { - backingField, - expectName, - annotation, - filterDefined, - collect, - createAndInsertImportDeclaration, - isDecoratorAnnotation, -} from '../common/arkts-utils'; +import { filterDefined, collect, createAndInsertImportDeclaration } from '../common/arkts-utils'; import { ProjectConfig } from '../common/plugin-context'; import { getEntryParams } from './entry-translators/utils'; import { factory as entryFactory } from './entry-translators/factory'; -import { hasDecoratorName, findDecoratorInfos } from './property-translators/utils'; +import { hasDecoratorName, findDecoratorInfos, backingField, expectName } 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, DecoratorNames, DECORATOR_TYPE_MAP, ENTRY_POINT_IMPORT_SOURCE_NAME, NavigationNames, EntryWrapperNames, + CustomComponentNames, } from '../common/predefines'; import { generateInstantiateInterop } from './interop/interop'; @@ -211,10 +202,6 @@ export class ComponentTransformer extends AbstractVisitor { return node; } const updateStatements: arkts.AstNode[] = []; - if (this.shouldAddLinkIntrinsic) { - const expr = arkts.factory.createIdentifier(DecoratorIntrinsicNames.LINK); - updateStatements.push(factory.createIntrinsicAnnotationDeclaration({ expr })); - } if (this.componentInterfaceCollection.length > 0) { this.insertComponentImport(); updateStatements.push(...this.componentInterfaceCollection); @@ -300,7 +287,7 @@ export class ComponentTransformer extends AbstractVisitor { const returnTypeAnnotation = arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID); const flags = arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD; const kind = arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD; - const key = arkts.factory.createIdentifier(CustomComponentNames.BUILDCOMPATIBLENODE); + const key = arkts.factory.createIdentifier(CustomComponentNames.BUILD_COMPATIBLE_NODE); return factory.createMethodDefinition({ key, @@ -401,7 +388,9 @@ export class ComponentTransformer extends AbstractVisitor { ), [ ...newDefinitionBody, - ...definition.body.map((st: arkts.AstNode) => factory.PreprocessClassPropertyModifier(st, scopeInfo.isDecl)), + ...definition.body.map((st: arkts.AstNode) => + factory.PreprocessClassPropertyModifier(st, scopeInfo.isDecl) + ), ...staticMethodBody, ], definition.modifiers, @@ -444,23 +433,21 @@ export class ComponentTransformer extends AbstractVisitor { } createInterfaceInnerMember(member: arkts.ClassProperty): arkts.ClassProperty[] { - const originalName: string = expectName(member.key); - const originMember: arkts.ClassProperty = propertyFactory.createOptionalClassProperty( - originalName, - member, - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC - ); const infos = findDecoratorInfos(member); - const buildParamInfo = infos.find((it) => - isDecoratorAnnotation(it.annotation, DecoratorNames.BUILDER_PARAM, true) - ); - if (!!buildParamInfo) { - originMember.setAnnotations([buildParamInfo.annotation.clone()]); - return [originMember]; - } - const targetInfo = infos.find((it) => DECORATOR_TYPE_MAP.has(it.name)); - if (!!targetInfo) { + const annotations = infos.map((it) => it.annotation.clone()); + const originalName: string = expectName(member.key); + const originMember: arkts.ClassProperty = propertyFactory + .createOptionalClassProperty( + originalName, + member, + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ) + .setAnnotations(annotations); + const typedAnnotations = infos + .filter((it) => DECORATOR_TYPE_MAP.has(it.name)) + .map((it) => it.annotation.clone()); + if (typedAnnotations.length > 0) { const newName: string = backingField(originalName); const newMember: arkts.ClassProperty = propertyFactory .createOptionalClassProperty( @@ -469,11 +456,7 @@ export class ComponentTransformer extends AbstractVisitor { undefined, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC ) - .setAnnotations([targetInfo.annotation.clone()]); - if (isDecoratorAnnotation(targetInfo.annotation, DecoratorNames.LINK, true)) { - this.shouldAddLinkIntrinsic = true; - originMember.setAnnotations([annotation(DecoratorIntrinsicNames.LINK)]); - } + .setAnnotations(typedAnnotations); return [originMember, newMember]; } return [originMember]; diff --git a/arkui-plugins/ui-plugins/entry-translators/factory.ts b/arkui-plugins/ui-plugins/entry-translators/factory.ts index e4dd29d22..d1b6ca2fa 100644 --- a/arkui-plugins/ui-plugins/entry-translators/factory.ts +++ b/arkui-plugins/ui-plugins/entry-translators/factory.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import * as path from 'path'; import { annotation, createAndInsertImportDeclaration } from '../../common/arkts-utils'; -import { ENTRY_POINT_IMPORT_SOURCE_NAME, EntryWrapperNames, NavigationNames } from '../../common/predefines'; +import { ENTRY_POINT_IMPORT_SOURCE_NAME, EntryWrapperNames, NavigationNames, NodeCacheNames } from '../../common/predefines'; import { ProjectConfig } from '../../common/plugin-context'; import { factory as uiFactory } from '../ui-factory'; import { getRelativePagePath } from './utils'; @@ -220,7 +220,7 @@ export class factory { member.scriptFunction.id.name === EntryWrapperNames.ENTRY_FUNC ) { addMemoAnnotation(member.scriptFunction); - arkts.NodeCache.getInstance().collect(member); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(member); } }); } diff --git a/arkui-plugins/ui-plugins/index.ts b/arkui-plugins/ui-plugins/index.ts index 1785e4854..b5f0dd198 100644 --- a/arkui-plugins/ui-plugins/index.ts +++ b/arkui-plugins/ui-plugins/index.ts @@ -115,7 +115,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { debugLog('[BEFORE STRUCT SCRIPT] script: ', script.dumpSrc()); debugDump( script.dumpSrc(), - getDumpFileName(0, 'SRC', 3, 'UI_AfterCheck_Begin'), + getDumpFileName(0, 'SRC', 5, 'UI_AfterCheck_Begin'), true, cachePath, program.fileNameWithExtension @@ -127,7 +127,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { debugLog('[AFTER STRUCT SCRIPT] script: ', script.dumpSrc()); debugDump( script.dumpSrc(), - getDumpFileName(0, 'SRC', 4, 'UI_AfterCheck_End'), + getDumpFileName(0, 'SRC', 6, 'UI_AfterCheck_End'), true, cachePath, program.fileNameWithExtension diff --git a/arkui-plugins/ui-plugins/interop/builder-interop.ts b/arkui-plugins/ui-plugins/interop/builder-interop.ts index f2073b52d..37ccba707 100644 --- a/arkui-plugins/ui-plugins/interop/builder-interop.ts +++ b/arkui-plugins/ui-plugins/interop/builder-interop.ts @@ -24,6 +24,7 @@ import { getWrapValue, setPropertyESValue } from './utils'; +import { NodeCacheNames } from '../../common/predefines'; interface builderParam { args: arkts.AstNode[], @@ -504,7 +505,7 @@ export function generateBuilderCompatible(node: arkts.CallExpression, moduleName updater, ] ); - arkts.NodeCache.getInstance().collect(result); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(result); return result; } diff --git a/arkui-plugins/ui-plugins/interop/initstatevar.ts b/arkui-plugins/ui-plugins/interop/initstatevar.ts index 464e6aef2..ec758222b 100644 --- a/arkui-plugins/ui-plugins/interop/initstatevar.ts +++ b/arkui-plugins/ui-plugins/interop/initstatevar.ts @@ -17,9 +17,8 @@ import * as arkts from '@koalaui/libarkts'; import { InteroperAbilityNames } from './predefines'; -import { annotation, backingField, isAnnotation } from '../../common/arkts-utils'; import { stateProxy, getWrapValue, setPropertyESValue } from './utils'; -import { hasDecorator } from '../property-translators/utils'; +import { backingField, hasDecorator } from '../property-translators/utils'; import { DecoratorNames } from '../../common/predefines'; diff --git a/arkui-plugins/ui-plugins/interop/interop.ts b/arkui-plugins/ui-plugins/interop/interop.ts index 737f1c916..e24404ab4 100644 --- a/arkui-plugins/ui-plugins/interop/interop.ts +++ b/arkui-plugins/ui-plugins/interop/interop.ts @@ -31,6 +31,7 @@ import { createInitReturn } from './utils'; import { ImportCollector } from '../../common/import-collector'; +import { NodeCacheNames } from '../../common/predefines'; function paramsLambdaDeclaration(name: string, args?: arkts.ObjectExpression): arkts.Statement[] { @@ -397,6 +398,6 @@ export function generateArkUICompatible(node: arkts.CallExpression): arkts.CallE arkts.factory.createThisExpression(), ] ); - arkts.NodeCache.getInstance().collect(result); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(result); return result; } \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/property-translators/builderParam.ts b/arkui-plugins/ui-plugins/property-translators/builderParam.ts index 41c616f60..6a95c4506 100644 --- a/arkui-plugins/ui-plugins/property-translators/builderParam.ts +++ b/arkui-plugins/ui-plugins/property-translators/builderParam.ts @@ -15,9 +15,8 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames } from '../../common/predefines'; -import { createGetter, createSetter, generateThisBacking, hasDecorator, removeDecorator, PropertyCache } from './utils'; +import { DecoratorNames, NodeCacheNames } from '../../common/predefines'; +import { createGetter, createSetter, generateThisBacking, hasDecorator, removeDecorator, PropertyCache, expectName, backingField } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { factory } from './factory'; @@ -49,7 +48,7 @@ export class BuilderParamTranslator extends PropertyTranslator implements Initia arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, true ); - arkts.NodeCache.getInstance().collect(field); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(field); const thisSetValue: arkts.Expression = generateThisBacking(newName, false, false); const getter: arkts.MethodDefinition = this.translateGetter( originalName, @@ -58,9 +57,9 @@ export class BuilderParamTranslator extends PropertyTranslator implements Initia ? generateThisBacking(newName, false, false) : generateThisBacking(newName, false, true) ); - arkts.NodeCache.getInstance().collect(getter); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(getter); const setter: arkts.MethodDefinition = this.translateSetter(originalName, propertyType?.clone(), thisSetValue); - arkts.NodeCache.getInstance().collect(setter); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(setter); return [field, getter, setter]; } @@ -115,10 +114,10 @@ export class BuilderParamInterfaceTranslator e } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.BUILDER_PARAM)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.BUILDER_PARAM)) { - return true; + if (arkts.isMethodDefinition(node)) { + return hasDecorator(node, DecoratorNames.BUILDER_PARAM); + } else if (arkts.isClassProperty(node)) { + return hasDecorator(node, DecoratorNames.BUILDER_PARAM); } return false; } @@ -142,7 +141,7 @@ export class BuilderParamInterfaceTranslator e }); method.setOverloads(newOverLoads); removeDecorator(method, DecoratorNames.BUILDER_PARAM); - arkts.NodeCache.getInstance().collect(method, { isGetter: true }); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method, { isGetter: true }); } else if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { const param = method.scriptFunction.params.at(0)! as arkts.ETSParameterExpression; const type = param.type; @@ -150,7 +149,7 @@ export class BuilderParamInterfaceTranslator e addMemoAnnotation(type); } removeDecorator(method, DecoratorNames.BUILDER_PARAM); - arkts.NodeCache.getInstance().collect(method, { isSetter: true }); + arkts.NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method, { isSetter: true }); } return method; } diff --git a/arkui-plugins/ui-plugins/property-translators/consume.ts b/arkui-plugins/ui-plugins/property-translators/consume.ts index 8bd40ec2e..a4d87d930 100644 --- a/arkui-plugins/ui-plugins/property-translators/consume.ts +++ b/arkui-plugins/ui-plugins/property-translators/consume.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, @@ -26,6 +25,9 @@ import { getValueInAnnotation, hasDecorator, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -125,10 +127,10 @@ export class ConsumeInterfaceTranslator extend } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.CONSUME)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.CONSUME)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.CONSUME); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.CONSUME); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/factory.ts b/arkui-plugins/ui-plugins/property-translators/factory.ts index 1843bc77a..d5dcd5a70 100644 --- a/arkui-plugins/ui-plugins/property-translators/factory.ts +++ b/arkui-plugins/ui-plugins/property-translators/factory.ts @@ -15,10 +15,9 @@ import * as arkts from '@koalaui/libarkts'; import { GenSymGenerator } from '../../common/gensym-generator'; -import { DecoratorNames, DECORATOR_TYPE_MAP, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, DECORATOR_TYPE_MAP, StateManagementTypes, CustomComponentNames } from '../../common/predefines'; import { factory as UIFactory } from '../ui-factory'; import { collectStateManagementTypeImport, getValueInAnnotation, hasDecorator, removeDecorator, generateThisBacking } from './utils'; -import { CustomComponentNames } from '../utils'; import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../../collectors/memo-collectors/utils'; import { annotation } from '../../common/arkts-utils'; diff --git a/arkui-plugins/ui-plugins/property-translators/link.ts b/arkui-plugins/ui-plugins/property-translators/link.ts index 65217d539..c2ba5db91 100644 --- a/arkui-plugins/ui-plugins/property-translators/link.ts +++ b/arkui-plugins/ui-plugins/property-translators/link.ts @@ -15,9 +15,7 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, createGetter, @@ -27,6 +25,9 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -144,10 +145,10 @@ export class LinkInterfaceTranslator extends I } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LINK)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LINK)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LINK); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/local.ts b/arkui-plugins/ui-plugins/property-translators/local.ts index e61a06d25..ee47694ad 100644 --- a/arkui-plugins/ui-plugins/property-translators/local.ts +++ b/arkui-plugins/ui-plugins/property-translators/local.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, @@ -26,6 +25,9 @@ import { hasDecorator, collectStateManagementTypeImport, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -123,10 +125,10 @@ export class LocalInterfaceTranslator extends } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.LOCAL); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts b/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts index 26053062d..092678be9 100644 --- a/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts +++ b/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -29,6 +28,9 @@ import { hasDecorator, PropertyCache, getValueInAnnotation, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; @@ -136,10 +138,10 @@ export class LocalStoragePropRefInterfaceTranslator< } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP_REF); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts index eae40f683..a7eb03b0c 100755 --- a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -29,6 +28,9 @@ import { hasDecorator, PropertyCache, getValueInAnnotation, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; @@ -136,10 +138,10 @@ export class LocalStorageLinkInterfaceTranslator< } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts b/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts index 58eec31cc..7862526ac 100644 --- a/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts +++ b/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts @@ -15,10 +15,12 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, StateManagementTypes } from '../../common/predefines'; import { + backingField, + checkIsNameStartWithBackingField, collectStateManagementTypeImport, + expectName, generateToRecord, hasDecorator, PropertyCache, @@ -211,10 +213,10 @@ export class LocalStoragePropInterfaceTranslator< } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/objectlink.ts b/arkui-plugins/ui-plugins/property-translators/objectlink.ts index 2c2089794..af38ec055 100644 --- a/arkui-plugins/ui-plugins/property-translators/objectlink.ts +++ b/arkui-plugins/ui-plugins/property-translators/objectlink.ts @@ -15,11 +15,12 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { + backingField, + checkIsNameStartWithBackingField, createGetter, + expectName, generateGetOrSetCall, generateThisBacking, generateToRecord, @@ -143,10 +144,10 @@ export class ObjectLinkInterfaceTranslator ext } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.OBJECT_LINK)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.OBJECT_LINK); } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.OBJECT_LINK)) { - return true; + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.OBJECT_LINK); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/observedTrack.ts b/arkui-plugins/ui-plugins/property-translators/observedTrack.ts index 28d0762e4..e26c2b296 100644 --- a/arkui-plugins/ui-plugins/property-translators/observedTrack.ts +++ b/arkui-plugins/ui-plugins/property-translators/observedTrack.ts @@ -14,9 +14,16 @@ */ import * as arkts from '@koalaui/libarkts'; -import { annotation, backingField, expectName } from '../../common/arkts-utils'; +import { annotation } from '../../common/arkts-utils'; import { DecoratorNames, StateManagementTypes } from '../../common/predefines'; -import { collectStateManagementTypeImport, hasDecorator, hasDecoratorName, removeDecorator } from './utils'; +import { + backingField, + collectStateManagementTypeImport, + expectName, + hasDecorator, + hasDecoratorName, + removeDecorator, +} from './utils'; import { ClassScopeInfo } from './types'; import { factory } from './factory'; @@ -57,7 +64,8 @@ export class ObservedTrackTranslator { const annotations: arkts.AnnotationUsage[] = [...this.property.annotations]; if ( !hasDecoratorName(this.property, DecoratorNames.JSONSTRINGIFYIGNORE) && - !hasDecoratorName(this.property, DecoratorNames.JSONRENAME)) { + !hasDecoratorName(this.property, DecoratorNames.JSONRENAME) + ) { annotations.push( annotation(DecoratorNames.JSONRENAME).addProperty( arkts.factory.createClassProperty( diff --git a/arkui-plugins/ui-plugins/property-translators/prop.ts b/arkui-plugins/ui-plugins/property-translators/prop.ts index df2bce793..a142274fb 100644 --- a/arkui-plugins/ui-plugins/property-translators/prop.ts +++ b/arkui-plugins/ui-plugins/property-translators/prop.ts @@ -15,9 +15,7 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, createGetter, @@ -27,6 +25,9 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -170,10 +171,10 @@ export class PropInterfaceTranslator extends I } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROP)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROP)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.PROP); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROP); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/propRef.ts b/arkui-plugins/ui-plugins/property-translators/propRef.ts index 483285506..b5dc5da0b 100644 --- a/arkui-plugins/ui-plugins/property-translators/propRef.ts +++ b/arkui-plugins/ui-plugins/property-translators/propRef.ts @@ -15,9 +15,7 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, createGetter, @@ -27,6 +25,9 @@ import { collectStateManagementTypeImport, hasDecorator, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -170,10 +171,10 @@ export class PropRefInterfaceTranslator extend } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROP_REF)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROP_REF)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.PROP_REF); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROP_REF); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/provide.ts b/arkui-plugins/ui-plugins/property-translators/provide.ts index c1141a5ac..6f04b2a76 100644 --- a/arkui-plugins/ui-plugins/property-translators/provide.ts +++ b/arkui-plugins/ui-plugins/property-translators/provide.ts @@ -15,9 +15,7 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { createGetter, generateToRecord, @@ -28,6 +26,9 @@ import { ProvideOptions, hasDecorator, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -137,10 +138,10 @@ export class ProvideInterfaceTranslator extend } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROVIDE)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROVIDE)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.PROVIDE); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROVIDE); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index f5d4a4724..d4086346b 100644 --- a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -15,10 +15,17 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, generateToRecord, generateThisBacking, createSetter2, PropertyCache } from './utils'; +import { + createGetter, + generateToRecord, + generateThisBacking, + createSetter2, + PropertyCache, + expectName, + backingField, +} from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; -import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; export class RegularPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { @@ -84,7 +91,7 @@ export class RegularPropertyTranslator extends PropertyTranslator implements Ini return createSetter2(originalName, typeAnnotation, statement); } - generateInitializeStruct(newName: string, originalName: string, value: arkts.Expression): arkts.AstNode { + generateInitializeStruct(newName: string, originalName: string, value: arkts.Expression | undefined): arkts.AstNode { const binaryItem = arkts.factory.createBinaryExpression( factory.createBlockStatementForOptionalExpression( arkts.factory.createIdentifier('initializers'), diff --git a/arkui-plugins/ui-plugins/property-translators/state.ts b/arkui-plugins/ui-plugins/property-translators/state.ts index 704a56f71..69abb7d00 100644 --- a/arkui-plugins/ui-plugins/property-translators/state.ts +++ b/arkui-plugins/ui-plugins/property-translators/state.ts @@ -15,9 +15,7 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { CustomComponentNames, DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { generateToRecord, createGetter, @@ -27,6 +25,9 @@ import { hasDecorator, collectStateManagementTypeImport, PropertyCache, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -130,10 +131,10 @@ export class StateInterfaceTranslator extends } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STATE)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STATE)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.STATE); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STATE); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/staticProperty.ts b/arkui-plugins/ui-plugins/property-translators/staticProperty.ts index 12e9535c5..5d86c0e24 100644 --- a/arkui-plugins/ui-plugins/property-translators/staticProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/staticProperty.ts @@ -15,10 +15,9 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, createSetter } from './utils'; +import { backingField, createGetter, createSetter, expectName } from './utils'; import { PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; -import { backingField, expectName } from '../../common/arkts-utils'; export class staticPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { diff --git a/arkui-plugins/ui-plugins/property-translators/storageProp.ts b/arkui-plugins/ui-plugins/property-translators/storageProp.ts index f1952c88d..9eebc2cb4 100644 --- a/arkui-plugins/ui-plugins/property-translators/storageProp.ts +++ b/arkui-plugins/ui-plugins/property-translators/storageProp.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -29,6 +28,9 @@ import { hasDecorator, PropertyCache, getValueInAnnotation, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; @@ -135,10 +137,10 @@ export class StoragePropInterfaceTranslator ex } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.STORAGE_PROP); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STORAGE_PROP); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts b/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts index d14668cc7..3c62cbfa3 100644 --- a/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts +++ b/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -29,6 +28,9 @@ import { hasDecorator, PropertyCache, getValueInAnnotation, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; @@ -137,10 +139,10 @@ export class StoragePropRefInterfaceTranslator< } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/storagelink.ts b/arkui-plugins/ui-plugins/property-translators/storagelink.ts index 579fe8832..e519529cf 100644 --- a/arkui-plugins/ui-plugins/property-translators/storagelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/storagelink.ts @@ -15,7 +15,6 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; @@ -29,6 +28,9 @@ import { hasDecorator, PropertyCache, getValueInAnnotation, + expectName, + backingField, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; @@ -134,10 +136,10 @@ export class StorageLinkInterfaceTranslator ex } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STORAGE_LINK)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STORAGE_LINK)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.name) && hasDecorator(node, DecoratorNames.STORAGE_LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STORAGE_LINK); } return false; } diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index e0a5f75db..ad33ade77 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -17,9 +17,7 @@ import * as arkts from '@koalaui/libarkts'; import { ImportCollector } from '../../common/import-collector'; import { isDecoratorAnnotation } from '../../common/arkts-utils'; import { - DecoratorIntrinsicNames, DecoratorNames, - DECORATOR_TYPE_MAP, StateManagementTypes, GetSetTypes, } from '../../common/predefines'; @@ -34,13 +32,6 @@ export interface DecoratorInfo { name: DecoratorNames; } -export function isDecoratorIntrinsicAnnotation( - anno: arkts.AnnotationUsage, - decoratorName: DecoratorIntrinsicNames -): boolean { - return !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName; -} - export function removeDecorator( property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, decoratorName: DecoratorNames, @@ -374,6 +365,27 @@ export function generateToRecord(newName: string, originalName: string): arkts.P ); } +export function expectName(node: arkts.AstNode | undefined): string { + if (!node) { + throw new Error('Expected an identifier, got empty node'); + } + if (!arkts.isIdentifier(node)) { + throw new Error('Expected an identifier, got: ' + arkts.nodeType(node).toString()); + } + return node.name; +} + +export function backingField(originalName: string): string { + return `${StateManagementTypes.BACKING}_${originalName}`; +} + +export function checkIsNameStartWithBackingField(node: arkts.AstNode | undefined): boolean { + if (!node || !arkts.isIdentifier(node)) { + return false; + } + return node.name.startsWith(StateManagementTypes.BACKING); +} + // CACHE export interface PropertyCachedBody { initializeBody?: arkts.AstNode[]; diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 1d7c8fc83..adacfba31 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -15,9 +15,6 @@ import * as arkts from '@koalaui/libarkts'; import { - BuilderLambdaNames, - CustomComponentNames, - CustomDialogNames, getCustomComponentOptionsName, getGettersFromClassDecl, getTypeNameFromTypeParameter, @@ -29,7 +26,7 @@ import { import { factory as UIFactory } from '../ui-factory'; import { factory as PropertyFactory } from '../property-translators/factory'; import { factory as BuilderLambdaFactory } from '../builder-lambda-translators/factory'; -import { backingField, collect, filterDefined } from '../../common/arkts-utils'; +import { collect, filterDefined } from '../../common/arkts-utils'; import { classifyObservedTrack, classifyProperty, @@ -58,6 +55,7 @@ import { DialogControllerInfo, } from './utils'; import { + backingField, collectStateManagementTypeImport, generateThisBacking, hasDecorator, @@ -74,6 +72,10 @@ import { StateManagementTypes, RESOURCE_TYPE, ARKUI_BUILDER_SOURCE_NAME, + CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, + BuilderLambdaNames, + CustomComponentNames, + CustomDialogNames, } from '../../common/predefines'; import { ObservedTrackTranslator } from '../property-translators/observedTrack'; import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; diff --git a/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts b/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts index 3101184cd..040c18422 100644 --- a/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts +++ b/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; import { ProjectConfig } from '../../common/plugin-context'; -import { collectCustomComponentScopeInfo, CustomComponentNames, isCustomComponentClass } from '../utils'; +import { collectCustomComponentScopeInfo, isCustomComponentClass } from '../utils'; import { CustomComponentScopeInfo, isResourceNode, @@ -33,6 +33,7 @@ import { ImportCollector } from '../../common/import-collector'; import { DeclarationCollector } from '../../common/declaration-collector'; import { PropertyCache } from '../property-translators/utils'; import { generateArkUICompatible, isArkUICompatible } from '../interop/interop'; +import { CustomComponentNames } from '../../common/predefines'; export class StructTransformer extends AbstractVisitor { private scope: ScopeInfoCollection; diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index fb952880f..47ffe07cb 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -16,7 +16,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as arkts from '@koalaui/libarkts'; -import { CustomComponentInfo, CustomDialogNames } from '../utils'; +import { CustomComponentInfo } from '../utils'; import { matchPrefix } from '../../common/arkts-utils'; import { ARKUI_IMPORT_PREFIX_NAMES, @@ -27,6 +27,7 @@ import { RESOURCE_TYPE, InnerComponentNames, ARKUI_FOREACH_SOURCE_NAME, + CustomDialogNames, } from '../../common/predefines'; import { DeclarationCollector } from '../../common/declaration-collector'; import { ProjectConfig } from '../../common/plugin-context'; @@ -104,7 +105,7 @@ export function isResourceNode(node: arkts.CallExpression, ignoreDecl: boolean = if (!decl) { return false; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName)) { return false; } @@ -337,7 +338,7 @@ export function checkRawfileResource( ): void { if (!fromOtherModule && !rawfileSet.has(rawfileStr.str)) { LogCollector.getInstance().collectLogInfo({ - type: LogType.ERROR, + level: LogType.ERROR, node: resourceNode, message: `No such '${rawfileStr.str}' resource in current module.`, code: '10904333', @@ -373,7 +374,7 @@ export function preCheckResourceData( } if (!!code && !!message) { LogCollector.getInstance().collectLogInfo({ - type: LogType.ERROR, + level: LogType.ERROR, node: resourceNode, message: message, code: code, @@ -448,7 +449,7 @@ function resourceCheck( } if (!!code && !!message) { LogCollector.getInstance().collectLogInfo({ - type: logType, + level: logType, node: resourceNode, message: message, code: code, diff --git a/arkui-plugins/ui-plugins/ui-factory.ts b/arkui-plugins/ui-plugins/ui-factory.ts index 9c204231a..af33cc9f2 100644 --- a/arkui-plugins/ui-plugins/ui-factory.ts +++ b/arkui-plugins/ui-plugins/ui-factory.ts @@ -15,15 +15,12 @@ import * as arkts from '@koalaui/libarkts'; import { - BuilderLambdaNames, CustomComponentAnontations, - CustomComponentNames, - CustomDialogNames, hasNullOrUndefinedType, hasPropertyInAnnotation, } from './utils'; import { PartialExcept, PartialNested, PartialNestedExcept } from '../common/safe-types'; -import { DecoratorNames } from '../common/predefines'; +import { BuilderLambdaNames, CustomComponentNames, CustomDialogNames, DecoratorNames } from '../common/predefines'; import { needDefiniteOrOptionalModifier } from './property-translators/utils'; import { addMemoAnnotation } from '../collectors/memo-collectors/utils'; diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index 5e541ac7f..507dc3f9f 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -18,47 +18,12 @@ import { matchPrefix } from '../common/arkts-utils'; import { ARKUI_IMPORT_PREFIX_NAMES, CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, + CustomComponentNames, + CustomDialogNames, StructDecoratorNames, } from '../common/predefines'; import { DeclarationCollector } from '../common/declaration-collector'; -export enum CustomComponentNames { - COMPONENT_BUILD_ORI = 'build', - COMPONENT_CONSTRUCTOR_ORI = 'constructor', - COMPONENT_CLASS_NAME = 'CustomComponent', - COMPONENT_V2_CLASS_NAME = 'CustomComponentV2', - BASE_CUSTOM_DIALOG_NAME = 'BaseCustomDialog', - COMPONENT_INTERFACE_PREFIX = '__Options_', - COMPONENT_INITIALIZE_STRUCT = '__initializeStruct', - COMPONENT_UPDATE_STRUCT = '__updateStruct', - COMPONENT_INITIALIZERS_NAME = 'initializers', - BUILDCOMPATIBLENODE = '_buildCompatibleNode', - OPTIONS = 'options', - PAGE_LIFE_CYCLE = 'PageLifeCycle', - LAYOUT_CALLBACK = 'LayoutCallback', -} - -export enum CustomDialogNames { - CUSTOM_DIALOG_ANNOTATION_NAME = 'CustomDialog', - CUSTOM_DIALOG_CONTROLLER = 'CustomDialogController', - CUSTOM_DIALOG_CONTROLLER_OPTIONS = 'CustomDialogControllerOptions', - SET_DIALOG_CONTROLLER_METHOD = '__setDialogController__', - CONTROLLER = 'controller', - OPTIONS_BUILDER = 'builder', - BASE_COMPONENT = 'baseComponent', - EXTENDABLE_COMPONENT = 'ExtendableComponent', - CUSTOM_BUILDER = 'CustomBuilder', -} - -export enum BuilderLambdaNames { - ANNOTATION_NAME = 'ComponentBuilder', - ORIGIN_METHOD_NAME = '$_instantiate', - TRANSFORM_METHOD_NAME = '_instantiateImpl', - STYLE_PARAM_NAME = 'style', - STYLE_ARROW_PARAM_NAME = 'instance', - CONTENT_PARAM_NAME = 'content', -} - // IMPORT export function findImportSourceByName(importName: string): string { const source = DeclarationCollector.getInstance().findExternalSourceFromName(importName); @@ -189,7 +154,7 @@ export function isCustomComponentAnnotation( if (!decl) { return false; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName || !matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, moduleName)) { return false; } @@ -242,7 +207,7 @@ export function collectCustomComponentScopeInfo( return { name: definition.ident.name, isDecl, - annotations: annotations as CustomComponentAnontations, + annotations, }; } diff --git a/arkui-plugins/ui-syntax-plugins/index.ts b/arkui-plugins/ui-syntax-plugins/index.ts index 250f6db37..1cd645a49 100644 --- a/arkui-plugins/ui-syntax-plugins/index.ts +++ b/arkui-plugins/ui-syntax-plugins/index.ts @@ -24,18 +24,89 @@ import { UISyntaxLinterVisitor } from './transformers/ui-syntax-linter-visitor'; import rules from './rules'; import { matchPrefix } from '../common/arkts-utils'; import { EXCLUDE_EXTERNAL_SOURCE_PREFIXES, tracePerformance } from './utils'; +import { debugDump, debugLog, getDumpFileName } from '../common/debug'; +import { UIVisitor } from '../collectors/ui-collectors/ui-visitor'; +import { MemoVisitor } from '../collectors/memo-collectors/memo-visitor'; +import { ProgramVisitor } from '../common/program-visitor'; export function uiSyntaxLinterTransform(): Plugins { - const processor = createUISyntaxRuleProcessor(rules); - const parsedTransformer = new ParsedUISyntaxLinterTransformer(processor); - const checkedTransformer = new CheckedUISyntaxLinterTransformer(processor); + // const processor = createUISyntaxRuleProcessor(rules); + // const parsedTransformer = new ParsedUISyntaxLinterTransformer(processor); + // const checkedTransformer = new CheckedUISyntaxLinterTransformer(processor); return { name: 'ui-syntax-plugin', - parsed: createTransformer('parsed', processor, parsedTransformer), - checked: createTransformer('checked', processor, checkedTransformer), + checked: collectAndLint, + // parsed: createTransformer('parsed', processor, parsedTransformer), + // checked: createTransformer('checked', processor, checkedTransformer), }; } +function collectAndLint(this: PluginContext): arkts.EtsScript | undefined { + let script: arkts.EtsScript | undefined; + console.log('[UI LINTER PLUGIN] AFTER CHECKED ENTER'); + // arkts.Performance.getInstance().memoryTrackerPrintCurrent('ArkTS:Parse'); + // arkts.Performance.getInstance().memoryTrackerReset(); + // arkts.Performance.getInstance().startMemRecord('Node:UIPlugin:AfterParse'); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + script = program.astNode; + const cachePath: string | undefined = this.getProjectConfig()?.cachePath; + // const canSkipPhases = program.canSkipPhases(); + debugLog('[BEFORE LINTER SCRIPT] script: ', script.dumpSrc()); + debugDump( + script.dumpSrc(), + getDumpFileName(0, 'SRC', 3, 'UI_LINTER_AfterCheck_Begin'), + true, + cachePath, + program.fileNameWithExtension + ); + arkts.Performance.getInstance().createEvent('ui-linter'); + program = parsedProgramVisit(program, this, false); + script = program.astNode; + arkts.Performance.getInstance().stopEvent('ui-linter', true); + debugLog('[AFTER LINTER SCRIPT] script: ', script.dumpSrc()); + debugDump( + script.dumpSrc(), + getDumpFileName(0, 'SRC', 4, 'UI_LINTER_AfterCheck_End'), + true, + cachePath, + program.fileNameWithExtension + ); + this.setArkTSAst(script); + // arkts.Performance.getInstance().memoryTrackerGetDelta('UIPlugin:AfterParse'); + // arkts.Performance.getInstance().memoryTrackerReset(); + // arkts.Performance.getInstance().stopMemRecord('Node:UIPlugin:AfterParse'); + console.log('[UI LINTER PLUGIN] AFTER CHECKED EXIT'); + return script; + } + console.log('[UI LINTER PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); + return script; +} + +function parsedProgramVisit( + program: arkts.Program, + context: PluginContext, + canSkipPhases: boolean = false +): arkts.Program { + if (canSkipPhases) { + debugLog('[SKIP PHASE] phase: ui-checker, moduleName: ', program.moduleName); + } else { + debugLog('[CANT SKIP PHASE] phase: ui-checker, moduleName: ', program.moduleName); + const uiCollector = new UIVisitor(); + const programVisitor = new ProgramVisitor({ + pluginName: uiSyntaxLinterTransform.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [uiCollector], + skipPrefixNames: EXCLUDE_EXTERNAL_SOURCE_PREFIXES, + pluginContext: context, + }); + program = programVisitor.programVisitor(program); + } + return program; +} + + function createTransformer( phase: string, processor: UISyntaxRuleProcessor, diff --git a/arkui-plugins/ui-syntax-plugins/utils/index.ts b/arkui-plugins/ui-syntax-plugins/utils/index.ts index 34866868f..d254430d6 100644 --- a/arkui-plugins/ui-syntax-plugins/utils/index.ts +++ b/arkui-plugins/ui-syntax-plugins/utils/index.ts @@ -486,7 +486,7 @@ export function getAnnotationUsageByName( return false; } const program = arkts.getProgramFromAstNode(annotationDeclaration); - if (!isFromPresetModules(program.moduleName)) { + if (!program || !isFromPresetModules(program.moduleName)) { return false; } return true; diff --git a/koala-wrapper/native/src/bridges.cc b/koala-wrapper/native/src/bridges.cc index 0a6ee1100..9edaa2367 100644 --- a/koala-wrapper/native/src/bridges.cc +++ b/koala-wrapper/native/src/bridges.cc @@ -261,6 +261,141 @@ KNativePointer impl_DeclarationFromIdentifier(KNativePointer context, KNativePoi } KOALA_INTEROP_2(DeclarationFromIdentifier, KNativePointer, KNativePointer, KNativePointer) +KNativePointer impl_ClassVariableDeclaration(KNativePointer context, KNativePointer classInstance) +{ + const auto _context = reinterpret_cast(context); + const auto _classInstance = reinterpret_cast(classInstance); + auto _typedTsType = GetImpl()->TypedTsType(_context, _classInstance); + if (_typedTsType == nullptr) { + return nullptr; + } + const auto _instanceType = reinterpret_cast(_typedTsType); + auto _typeVar = GetImpl()->TypeVariable(_context, _instanceType); + if (_typeVar == nullptr) { + return nullptr; + } + const auto result = reinterpret_cast(GetImpl()->VariableDeclaration(_context, _typeVar)); + const auto declNode = GetImpl()->DeclNode(_context, result); + return declNode; +} +KOALA_INTEROP_2(ClassVariableDeclaration, KNativePointer, KNativePointer, KNativePointer); + +static KNativePointer findPropertyInClassDefinition(KNativePointer context, KNativePointer classInstance, char *keyName) +{ + const auto _context = reinterpret_cast(context); + const auto _instance = reinterpret_cast(classInstance); + std::size_t bodySize = 0; + const auto _body = GetImpl()->ClassDefinitionBody(_context, _instance, &bodySize); + if (_body == nullptr) { + return nullptr; + } + const auto _bodyInstance = reinterpret_cast(_body); + for (std::size_t i = 0; i < bodySize; i++) { + const auto _member = reinterpret_cast(_bodyInstance[i]); + const auto _key = reinterpret_cast(GetImpl()->ClassElementKey(_context, _member)); + if (strcmp(GetImpl()->IdentifierName(_context, _key), keyName) == 0) { + return _member; + } + } + return nullptr; +} + +static KNativePointer findPropertyInTSInterfaceDeclaration(KNativePointer context, KNativePointer classInstance, char *keyName) +{ + const auto _context = reinterpret_cast(context); + const auto _instance = reinterpret_cast(classInstance); + const auto _body = GetImpl()->TSInterfaceDeclarationBody(_context, _instance); + if (_body == nullptr) { + return nullptr; + } + const auto _bodyInstance = reinterpret_cast(_body); + std::size_t bodySize = 0; + const auto _bodyBody = GetImpl()->TSInterfaceBodyBodyConst(_context, _bodyInstance, &bodySize); + if (_bodyBody == nullptr) { + return nullptr; + } + const auto _bodyBodyInstance = reinterpret_cast(_bodyBody); + for (std::size_t i = 0; i < bodySize; i++) { + const auto _member = reinterpret_cast(_bodyBodyInstance[i]); + const auto _key = reinterpret_cast(GetImpl()->ClassElementKey(_context, _member)); + if (strcmp(GetImpl()->IdentifierName(_context, _key), keyName) == 0) { + return _member; + } + } + return nullptr; +} + +KNativePointer impl_DeclarationFromProperty(KNativePointer context, KNativePointer property) +{ + const auto _context = reinterpret_cast(context); + const auto _property = reinterpret_cast(property); + auto _key = GetImpl()->PropertyKey(_context, _property); + if (_key == nullptr) { + return nullptr; + } + auto _parent = GetImpl()->AstNodeParent(_context, _property); + if (_parent == nullptr) { + return nullptr; + } + const auto _parentInstance = reinterpret_cast(_parent); + auto _decl = impl_ClassVariableDeclaration(_context, _parentInstance); + if (_decl == nullptr) { + return nullptr; + } + const auto _declInstance = reinterpret_cast(_decl); + const auto _keyInstance = reinterpret_cast(_key); + auto _keyName = GetImpl()->IdentifierName(_context, _keyInstance); + if (GetImpl()->IsClassDefinition(_declInstance)) { + return findPropertyInClassDefinition(_context, _declInstance, _keyName); + } + if (GetImpl()->IsTSInterfaceDeclaration(_declInstance)) { + return findPropertyInTSInterfaceDeclaration(_context, _declInstance, _keyName); + } + return nullptr; +} +KOALA_INTEROP_2(DeclarationFromProperty, KNativePointer, KNativePointer, KNativePointer); + +KNativePointer impl_DeclarationFromMemberExpression(KNativePointer context, KNativePointer nodePtr) +{ + const auto _context = reinterpret_cast(context); + const auto _node = reinterpret_cast(nodePtr); + auto _object = GetImpl()->MemberExpressionObject(_context, _node); + auto _property = GetImpl()->MemberExpressionProperty(_context, _node); + if (_property == nullptr) { + return nullptr; + } + const auto _propertyInstance = reinterpret_cast(_property); + if (GetImpl()->IsNumberLiteral(_propertyInstance) && _object != nullptr) { + const auto _objectInstance = reinterpret_cast(_object); + if (GetImpl()->IsMemberExpression(_objectInstance)) { + return impl_DeclarationFromMemberExpression(_context, _objectInstance); + } + return GetImpl()->DeclarationFromIdentifier(_context, _objectInstance); + } + if (GetImpl()->IsMemberExpression(_propertyInstance)) { + return impl_DeclarationFromMemberExpression(_context, _propertyInstance); + } + return GetImpl()->DeclarationFromIdentifier(_context, _propertyInstance); +} +KOALA_INTEROP_2(DeclarationFromMemberExpression, KNativePointer, KNativePointer, KNativePointer); + +KNativePointer impl_DeclarationFromAstNode(KNativePointer context, KNativePointer nodePtr) +{ + const auto _context = reinterpret_cast(context); + const auto _node = reinterpret_cast(nodePtr); + if (GetImpl()->IsMemberExpression(_node)) { + return impl_DeclarationFromMemberExpression(_context, _node); + } + if (GetImpl()->IsObjectExpression(_node)) { + return impl_ClassVariableDeclaration(_context, _node); + } + if (GetImpl()->IsProperty(_node)) { + return impl_DeclarationFromProperty(_context, _node); + } + return GetImpl()->DeclarationFromIdentifier(_context, _node); +} +KOALA_INTEROP_2(DeclarationFromAstNode, KNativePointer, KNativePointer, KNativePointer); + static KNativePointer impl_ProgramExternalSources(KNativePointer contextPtr, KNativePointer instancePtr) { auto context = reinterpret_cast(contextPtr); @@ -468,25 +603,6 @@ KNativePointer impl_ProgramAbsoluteNameConst(KNativePointer contextPtr, KNativeP } KOALA_INTEROP_2(ProgramAbsoluteNameConst, KNativePointer, KNativePointer, KNativePointer); -KNativePointer impl_ClassVariableDeclaration(KNativePointer context, KNativePointer classInstance) -{ - const auto _context = reinterpret_cast(context); - const auto _classInstance = reinterpret_cast(classInstance); - auto _typedTsType = GetImpl()->TypedTsType(_context, _classInstance); - if (_typedTsType == nullptr) { - return nullptr; - } - const auto _instanceType = reinterpret_cast(_typedTsType); - auto _typeVar = GetImpl()->TypeVariable(_context, _instanceType); - if (_typeVar == nullptr) { - return nullptr; - } - const auto result = reinterpret_cast(GetImpl()->VariableDeclaration(_context, _typeVar)); - const auto declNode = GetImpl()->DeclNode(_context, result); - return declNode; -} -KOALA_INTEROP_2(ClassVariableDeclaration, KNativePointer, KNativePointer, KNativePointer) - KBoolean impl_IsMethodDefinition(KNativePointer nodePtr) { auto node = reinterpret_cast(nodePtr); diff --git a/koala-wrapper/native/src/common.cc b/koala-wrapper/native/src/common.cc index 29baa82db..2c3931ac6 100644 --- a/koala-wrapper/native/src/common.cc +++ b/koala-wrapper/native/src/common.cc @@ -266,10 +266,77 @@ KNativePointer impl_AstNodeProgram(KNativePointer contextPtr, KNativePointer ins if (GetImpl()->AstNodeIsProgramConst(_context, _receiver)) { return GetImpl()->ETSModuleProgram(_context, _receiver); } - return impl_AstNodeProgram(_context, GetImpl()->AstNodeParent(_context, _receiver)); + auto parent = GetImpl()->AstNodeParent(_context, _receiver); + if (parent == nullptr) { + return nullptr; + } + return impl_AstNodeProgram(_context, parent); } KOALA_INTEROP_2(AstNodeProgram, KNativePointer, KNativePointer, KNativePointer) +thread_local KBoolean targetChildFound = false; +thread_local es2panda_AstNode *targetInnerChild = nullptr; +thread_local KInt targetAstNodeType = -1; + +static void findNodeInnerChild(es2panda_AstNode *node, void *arg) +{ + if (targetInnerChild == node) { + targetChildFound = true; + } +} + +KBoolean impl_AstNodeFindNodeInInnerChild(KNativePointer contextPtr, KNativePointer instancePtr, KNativePointer tartgetPtr) +{ + if (tartgetPtr == nullptr) { + return false; + } + auto _context = reinterpret_cast(contextPtr); + auto _receiver = reinterpret_cast(instancePtr); + auto _target = reinterpret_cast(tartgetPtr); + targetChildFound = false; + targetInnerChild = _target; + GetImpl()->AstNodeForEach(_receiver, findNodeInnerChild, _context); + return targetChildFound; +} +KOALA_INTEROP_3(AstNodeFindNodeInInnerChild, KBoolean, KNativePointer, KNativePointer, KNativePointer); + +static void findInnerChild(es2panda_AstNode *node, void *arg) +{ + auto *context = static_cast(arg); + if (targetAstNodeType == GetImpl()->AstNodeTypeConst(context, node)) { + targetInnerChild = node; + } +} + +KNativePointer impl_AstNodeFindInnerChild(KNativePointer contextPtr, KNativePointer instancePtr, KInt AstNodeType) +{ + auto _context = reinterpret_cast(contextPtr); + auto _receiver = reinterpret_cast(instancePtr); + targetAstNodeType = AstNodeType; + + GetImpl()->AstNodeForEach(_receiver, findInnerChild, _context); + return targetInnerChild; +} +KOALA_INTEROP_3(AstNodeFindInnerChild, KNativePointer, KNativePointer, KNativePointer, KInt); + +KNativePointer impl_AstNodeFindOuterParent(KNativePointer contextPtr, KNativePointer instancePtr, KInt AstNodeType) +{ + auto _context = reinterpret_cast(contextPtr); + auto _receiver = reinterpret_cast(instancePtr); + if (GetImpl()->AstNodeIsProgramConst(_context, _receiver)) { + return nullptr; + } + if (AstNodeType == GetImpl()->AstNodeTypeConst(_context, _receiver)) { + return _receiver; + } + auto parent = GetImpl()->AstNodeParent(_context, _receiver); + if (parent == nullptr) { + return nullptr; + } + return impl_AstNodeFindOuterParent(_context, parent, AstNodeType); +} +KOALA_INTEROP_3(AstNodeFindOuterParent, KNativePointer, KNativePointer, KNativePointer, KInt); + thread_local es2panda_AstNode *cachedParentNode; thread_local es2panda_Context *cachedContext; diff --git a/koala-wrapper/src/Es2pandaNativeModule.ts b/koala-wrapper/src/Es2pandaNativeModule.ts index 1fcdcdd4f..65eeea3ad 100644 --- a/koala-wrapper/src/Es2pandaNativeModule.ts +++ b/koala-wrapper/src/Es2pandaNativeModule.ts @@ -713,6 +713,15 @@ export class Es2pandaNativeModule { _DeclarationFromIdentifier(context: KPtr, identifier: KPtr): KPtr { throw new Error('Not implemented'); } + _DeclarationFromProperty(context: KPtr, property: KPtr): KPtr { + throw new Error('Not implemented'); + } + _DeclarationFromMemberExpression(context: KPtr, expression: KPtr): KPtr { + throw new Error('Not implemented'); + } + _DeclarationFromAstNode(context: KPtr, node: KPtr): KPtr { + throw new Error('Not implemented'); + } _IsTSInterfaceDeclaration(ast: KNativePointer): KBoolean { throw new Error('Not implemented'); } @@ -954,6 +963,18 @@ export class Es2pandaNativeModule { _CallExpressionIsTrailingCallConst(context: KNativePointer, node: KNativePointer): boolean { throw new Error('CallExpressionIsTrailingCallConst was not overloaded by native module initialization'); } + + _AstNodeFindNodeInInnerChild(context: KNativePointer, node: KNativePointer, target: KNativePointer): boolean { + throw new Error('AstNodeFindNodeInInnerChild was not overloaded by native module initialization'); + } + + _AstNodeFindInnerChild(context: KNativePointer, node: KNativePointer, nodeType: KInt): KNativePointer { + throw new Error('AstNodeFindInnerChild was not overloaded by native module initialization'); + } + + _AstNodeFindOuterParent(context: KNativePointer, node: KNativePointer, nodeType: KInt): KNativePointer { + throw new Error('AstNodeFindOuterParent was not overloaded by native module initialization'); + } } export function initEs2panda(): Es2pandaNativeModule { diff --git a/koala-wrapper/src/arkts-api/class-by-peer.ts b/koala-wrapper/src/arkts-api/class-by-peer.ts index 4306cff12..515502e68 100644 --- a/koala-wrapper/src/arkts-api/class-by-peer.ts +++ b/koala-wrapper/src/arkts-api/class-by-peer.ts @@ -13,29 +13,11 @@ * limitations under the License. */ -import { Es2pandaAstNodeType } from '../Es2pandaEnums'; +import { KNativePointer, nullptr } from '@koalaui/interop'; import { throwError } from '../utils'; import { global } from './static/global'; -import { KNativePointer, nullptr } from '@koalaui/interop'; import { AstNode, UnsupportedNode } from './peers/AstNode'; - -type AstNodeConstructor = new (peer: KNativePointer) => AstNode; -export const nodeByType = new Map([]); - -const cache = new Map(); -export function clearNodeCache(): void { - cache.clear(); -} - -export function getOrPut(peer: KNativePointer, create: (peer: KNativePointer) => AstNode): AstNode { - if (cache.has(peer)) { - return cache.get(peer)!; - } - - const newNode = create(peer); - cache.set(peer, newNode); - return newNode; -} +import { getOrPut, nodeByType } from './node-by-type'; export function classByPeer(peer: KNativePointer): T { if (peer === nullptr) { diff --git a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts index 73fade7ba..6b0de31f4 100644 --- a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts +++ b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts @@ -81,6 +81,7 @@ import { ForOfStatement, SwitchStatement, SwitchCaseStatement, + SpreadElement, } from '../../generated'; import { updateIdentifier } from '../node-utilities/Identifier'; import { updateCallExpression } from '../node-utilities/CallExpression'; @@ -142,6 +143,7 @@ import { updateForInStatement } from '../node-utilities/ForInStatement'; import { updateForOfStatement } from '../node-utilities/ForOfStatement'; import { updateSwitchStatement } from '../node-utilities/SwitchStatement'; import { updateSwitchCaseStatement } from '../node-utilities/SwitchCaseStatement'; +import { updateSpreadElement } from '../node-utilities/SpreadElement'; export const factory = { get createIdentifier(): (...args: Parameters) => Identifier { @@ -617,6 +619,12 @@ export const factory = { get updateSwitchCaseStatement(): (...args: Parameters) => SwitchCaseStatement { return updateSwitchCaseStatement; }, + get createSpreadElement(): (...args: Parameters) => SpreadElement { + return SpreadElement.createSpreadElement; + }, + get updateSpreadElement(): (...args: Parameters) => SpreadElement { + return updateSpreadElement; + }, /** @deprecated */ createTypeParameter1_(name: Identifier, constraint?: TypeNode, defaultType?: TypeNode) { return TSTypeParameter.createTSTypeParameter(Identifier.create1Identifier(name.name), constraint, defaultType); diff --git a/koala-wrapper/src/arkts-api/index.ts b/koala-wrapper/src/arkts-api/index.ts index e09dfff6d..cf6cda515 100644 --- a/koala-wrapper/src/arkts-api/index.ts +++ b/koala-wrapper/src/arkts-api/index.ts @@ -71,6 +71,7 @@ export * from '../generated/peers/BreakStatement'; export * from '../generated/peers/SwitchCaseStatement'; export * from '../generated/peers/SwitchStatement'; +export * from './class-by-peer'; export * from './types'; export * from './utilities/private'; export * from './utilities/public'; diff --git a/koala-wrapper/src/arkts-api/node-by-type.ts b/koala-wrapper/src/arkts-api/node-by-type.ts new file mode 100644 index 000000000..b12dc0cf1 --- /dev/null +++ b/koala-wrapper/src/arkts-api/node-by-type.ts @@ -0,0 +1,35 @@ +/* + * 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 { KNativePointer } from '@koalaui/interop'; +import { Es2pandaAstNodeType } from '../Es2pandaEnums'; +import type { AstNode } from './peers/AstNode'; + +export const nodeByType = new Map([]); + +const cache = new Map(); +export function clearNodeCache(): void { + cache.clear(); +} + +export function getOrPut(peer: KNativePointer, create: (peer: KNativePointer) => AstNode): AstNode { + if (cache.has(peer)) { + return cache.get(peer)!; + } + + const newNode = create(peer); + cache.set(peer, newNode); + return newNode; +} \ No newline at end of file diff --git a/koala-wrapper/src/arkts-api/node-utilities/ArrowFunctionExpression.ts b/koala-wrapper/src/arkts-api/node-utilities/ArrowFunctionExpression.ts index a787698d7..8c38e1244 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ArrowFunctionExpression.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ArrowFunctionExpression.ts @@ -16,7 +16,7 @@ import { ScriptFunction } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; import { ArrowFunctionExpression } from '../types'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateArrowFunctionExpression( @@ -33,8 +33,8 @@ export function updateArrowFunctionExpression( (node: ArrowFunctionExpression, original: ArrowFunctionExpression) => node.setAnnotations(original.annotations) ); const newNode = update(original, func); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/CallExpression.ts b/koala-wrapper/src/arkts-api/node-utilities/CallExpression.ts index 843798827..1b43a99b9 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/CallExpression.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/CallExpression.ts @@ -17,7 +17,7 @@ import { TypeNode } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; import { AstNode } from '../peers/AstNode'; import { CallExpression } from '../types'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateCallExpression( @@ -43,8 +43,8 @@ export function updateCallExpression( !!original.trailingBlock ? node.setTralingBlock(original.trailingBlock) : node ); const newNode = update(original, expression, typeArguments, args, isOptional, trailingComma); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/ClassProperty.ts b/koala-wrapper/src/arkts-api/node-utilities/ClassProperty.ts index 1d31c2858..1ce11b242 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ClassProperty.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ClassProperty.ts @@ -18,7 +18,7 @@ import { isSameNativeObject } from '../peers/ArktsObject'; import { updateThenAttach } from '../utilities/private'; import { classPropertySetOptional, hasModifierFlag } from '../utilities/public'; import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; export function updateClassProperty( original: ClassProperty, @@ -49,8 +49,8 @@ export function updateClassProperty( } ); const newNode = update(original, key, value, typeAnnotation, modifiers, isComputed); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/ETSFunctionType.ts b/koala-wrapper/src/arkts-api/node-utilities/ETSFunctionType.ts index c4e441974..622080ee1 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ETSFunctionType.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ETSFunctionType.ts @@ -17,7 +17,7 @@ import { ETSFunctionType, FunctionSignature } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; import { attachModifiers, updateThenAttach } from '../utilities/private'; import { Es2pandaScriptFunctionFlags } from '../../generated/Es2pandaEnums'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; export function updateETSFunctionType( original: ETSFunctionType, @@ -40,8 +40,8 @@ export function updateETSFunctionType( (node: ETSFunctionType, original: ETSFunctionType) => node.setAnnotations(original.annotations) ); const newNode = update(original, signature, funcFlags); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/ETSParameterExpression.ts b/koala-wrapper/src/arkts-api/node-utilities/ETSParameterExpression.ts index 23923cd75..bef1df368 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ETSParameterExpression.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ETSParameterExpression.ts @@ -17,7 +17,7 @@ import { Identifier } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; import { AstNode } from '../peers/AstNode'; import { ETSParameterExpression } from '../types'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateETSParameterExpression( @@ -41,8 +41,8 @@ export function updateETSParameterExpression( }, ); const newNode = update(original, identifier, initializer); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/ETSUnionType.ts b/koala-wrapper/src/arkts-api/node-utilities/ETSUnionType.ts index 07ab40282..c2a2ce687 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ETSUnionType.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ETSUnionType.ts @@ -15,7 +15,7 @@ import { ETSUnionType, TypeNode } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateETSUnionType(original: ETSUnionType, types: readonly TypeNode[]): ETSUnionType { @@ -25,8 +25,8 @@ export function updateETSUnionType(original: ETSUnionType, types: readonly TypeN const update = updateThenAttach(ETSUnionType.updateETSUnionType, attachModifiers); const newNode = update(original, types); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/Identifier.ts b/koala-wrapper/src/arkts-api/node-utilities/Identifier.ts index 3a1fff783..98928baf9 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/Identifier.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/Identifier.ts @@ -15,7 +15,7 @@ import { Identifier, TypeNode } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateIdentifier(original: Identifier, name: string, typeAnnotation?: TypeNode): Identifier { @@ -25,8 +25,8 @@ export function updateIdentifier(original: Identifier, name: string, typeAnnotat const update = updateThenAttach(Identifier.update2Identifier, attachModifiers); const newNode = update(original, name, typeAnnotation); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/MethodDefinition.ts b/koala-wrapper/src/arkts-api/node-utilities/MethodDefinition.ts index 6318a0c84..6c8e52b84 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/MethodDefinition.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/MethodDefinition.ts @@ -20,7 +20,7 @@ import { MethodDefinition } from '../types'; import { updateThenAttach } from '../utilities/private'; import { Es2pandaMethodDefinitionKind } from '../../generated/Es2pandaEnums'; import { ScriptFunction } from '../../generated'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; export function updateMethodDefinition( original: MethodDefinition, @@ -44,8 +44,8 @@ export function updateMethodDefinition( node.setOverloads(original.overloads) ); const newNode = update(original, kind, key, value, modifiers, isComputed); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/Property.ts b/koala-wrapper/src/arkts-api/node-utilities/Property.ts index fdb1443c5..7812409bf 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/Property.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/Property.ts @@ -15,7 +15,7 @@ import { Expression, Property } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateProperty(original: Property, key?: Expression, value?: Expression): Property { @@ -25,8 +25,8 @@ export function updateProperty(original: Property, key?: Expression, value?: Exp const update = updateThenAttach(Property.updateProperty, attachModifiers); const newNode = update(original, key, value); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; diff --git a/koala-wrapper/src/arkts-api/node-utilities/ReturnStatement.ts b/koala-wrapper/src/arkts-api/node-utilities/ReturnStatement.ts index 984e0aa5d..c34bd24f3 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ReturnStatement.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ReturnStatement.ts @@ -15,7 +15,7 @@ import { Expression, ReturnStatement } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateReturnStatement(original: ReturnStatement, argument?: Expression): ReturnStatement { @@ -25,8 +25,8 @@ export function updateReturnStatement(original: ReturnStatement, argument?: Expr const update = updateThenAttach(ReturnStatement.update1ReturnStatement, attachModifiers); const newNode = update(original, argument); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/ScriptFunction.ts b/koala-wrapper/src/arkts-api/node-utilities/ScriptFunction.ts index 16e30342a..6f5f55bc9 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/ScriptFunction.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/ScriptFunction.ts @@ -16,7 +16,7 @@ import { FunctionSignature, ScriptFunction } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; import { AstNode } from '../peers/AstNode'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { updateThenAttach } from '../utilities/private'; export function updateScriptFunction( @@ -44,8 +44,8 @@ export function updateScriptFunction( (node: ScriptFunction, original: ScriptFunction) => node.setAnnotations(original.annotations) ); const newNode = update(original, databody, datasignature, datafuncFlags, dataflags); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/SpreadElement.ts b/koala-wrapper/src/arkts-api/node-utilities/SpreadElement.ts new file mode 100644 index 000000000..f8e24176d --- /dev/null +++ b/koala-wrapper/src/arkts-api/node-utilities/SpreadElement.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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 { Expression, SpreadElement } from '../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { attachModifiers, updateThenAttach } from '../utilities/private'; +import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; +import { global } from '../static/global'; + +export function updateSpreadElement( + original: SpreadElement, + nodeType: Es2pandaAstNodeType, + argument?: Expression +): SpreadElement { + const originalNodeType = global.generatedEs2panda._AstNodeTypeConst(global.context, original.peer); + if (isSameNativeObject(argument, original.argument) && isSameNativeObject(nodeType, originalNodeType)) { + return original; + } + + const update = updateThenAttach(SpreadElement.updateSpreadElement, attachModifiers); + return update(original, nodeType, argument); +} diff --git a/koala-wrapper/src/arkts-api/node-utilities/TSTypeAliasDeclaration.ts b/koala-wrapper/src/arkts-api/node-utilities/TSTypeAliasDeclaration.ts index a1d47e0e1..16812cd1f 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/TSTypeAliasDeclaration.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/TSTypeAliasDeclaration.ts @@ -15,7 +15,7 @@ import { Identifier, TSTypeAliasDeclaration, TSTypeParameterDeclaration, TypeNode } from '../../generated'; import { isSameNativeObject } from '../peers/ArktsObject'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; import { attachModifiers, updateThenAttach } from '../utilities/private'; export function updateTSTypeAliasDeclaration( @@ -38,8 +38,8 @@ export function updateTSTypeAliasDeclaration( (node: TSTypeAliasDeclaration, original: TSTypeAliasDeclaration) => node.setAnnotations(original.annotations) ); const newNode = update(original, id, typeParams, typeAnnotation); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/node-utilities/VariableDeclarator.ts b/koala-wrapper/src/arkts-api/node-utilities/VariableDeclarator.ts index 1f1739da2..ebb556c3d 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/VariableDeclarator.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/VariableDeclarator.ts @@ -19,7 +19,7 @@ import { VariableDeclarator } from '../types'; import { attachModifiers, updateThenAttach } from '../utilities/private'; import { Es2pandaVariableDeclaratorFlag } from '../../generated/Es2pandaEnums'; import { AstNode } from '../peers/AstNode'; -import { NodeCache } from '../utilities/nodeCache'; +import { NodeCacheFactory } from '../utilities/nodeCache'; export function updateVariableDeclarator( original: VariableDeclarator, @@ -37,8 +37,8 @@ export function updateVariableDeclarator( const update = updateThenAttach(VariableDeclarator.update, attachModifiers); const newNode = update(original, flag, name, initializer); - if (NodeCache.getInstance().has(original)) { - NodeCache.getInstance().refresh(original, newNode); + if (NodeCacheFactory.getInstance().has(original)) { + NodeCacheFactory.getInstance().refresh(original, newNode); } return newNode; } diff --git a/koala-wrapper/src/arkts-api/peers/AstNode.ts b/koala-wrapper/src/arkts-api/peers/AstNode.ts index 6d49f5da9..2b0294f38 100644 --- a/koala-wrapper/src/arkts-api/peers/AstNode.ts +++ b/koala-wrapper/src/arkts-api/peers/AstNode.ts @@ -20,6 +20,8 @@ import { throwError } from '../../utils'; import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; import { ArktsObject } from './ArktsObject'; import { SourcePosition } from './SourcePosition'; +import { nodeByType } from '../node-by-type'; +import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; export abstract class AstNode extends ArktsObject { protected constructor(peer: KNativePointer) { @@ -103,6 +105,28 @@ export abstract class AstNode extends ArktsObject { return clonedNode as this; } + public findNodeInInnerChild(node: AstNode): boolean { + return global.es2panda._AstNodeFindNodeInInnerChild(global.context, this.peer, node.peer); + } + + public findInnerChild(nodeType: Es2pandaAstNodeType): T | undefined { + const childNodePeer = global.es2panda._AstNodeFindInnerChild(global.context, this.peer, nodeType); + if (childNodePeer === nullptr) { + return undefined; + } + const Node = nodeByType.get(nodeType) ?? UnsupportedNode; + return new Node(childNodePeer) as T; + } + + public findOuterParent(nodeType: Es2pandaAstNodeType): T | undefined { + const parentNodePeer = global.es2panda._AstNodeFindOuterParent(global.context, this.peer, nodeType); + if (parentNodePeer === nullptr) { + return undefined; + } + const Node = nodeByType.get(nodeType) ?? UnsupportedNode; + return new Node(parentNodePeer) as T; + } + public get parent(): AstNode | undefined { const parent = global.generatedEs2panda._AstNodeParent(global.context, this.peer); return unpackNode(parent); diff --git a/koala-wrapper/src/arkts-api/static/globalUtils.ts b/koala-wrapper/src/arkts-api/static/globalUtils.ts index 8e3a91074..29a9123ab 100644 --- a/koala-wrapper/src/arkts-api/static/globalUtils.ts +++ b/koala-wrapper/src/arkts-api/static/globalUtils.ts @@ -16,7 +16,7 @@ import { KNativePointer } from "@koalaui/interop"; import { Context } from "../peers/Context"; import { global } from "./global"; -import { clearNodeCache } from "../class-by-peer"; +import { clearNodeCache } from "../node-by-type"; export function getOrUpdateGlobalContext(peer: KNativePointer): Context { if (!global.compilerContext || global.context !== peer) { diff --git a/koala-wrapper/src/arkts-api/types.ts b/koala-wrapper/src/arkts-api/types.ts index d73f539d0..772fc39fb 100644 --- a/koala-wrapper/src/arkts-api/types.ts +++ b/koala-wrapper/src/arkts-api/types.ts @@ -39,11 +39,9 @@ import { import { proceedToState } from './utilities/public'; import { Es2pandaAstNodeType } from '../Es2pandaEnums'; import { AstNode } from './peers/AstNode'; -import { ArktsObject } from './peers/ArktsObject'; import { Config } from './peers/Config'; import { Context } from './peers/Context'; -import * as path from 'node:path'; -import { nodeByType } from './class-by-peer'; +import { nodeByType } from './node-by-type'; import { MemberExpression } from './to-be-generated/MemberExpression'; import { AnnotationUsage, diff --git a/koala-wrapper/src/arkts-api/utilities/nodeCache.ts b/koala-wrapper/src/arkts-api/utilities/nodeCache.ts index 0843ee6b6..d08fdb129 100644 --- a/koala-wrapper/src/arkts-api/utilities/nodeCache.ts +++ b/koala-wrapper/src/arkts-api/utilities/nodeCache.ts @@ -17,7 +17,7 @@ import { KNativePointer } from '@koalaui/interop'; import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; import { AstNode, UnsupportedNode } from '../peers/AstNode'; import { global } from '../static/global'; -import { getOrPut, nodeByType } from '../class-by-peer'; +import { getOrPut, nodeByType } from '../node-by-type'; export interface AstNodeCacheValue { peer: KNativePointer; @@ -25,32 +25,18 @@ export interface AstNodeCacheValue { metadata?: AstNodeCacheValueMetadata; } -export interface AstNodeCacheValueMetadata { - callName?: string; - hasReceiver?: boolean; - isSetter?: boolean; - isGetter?: boolean; - hasMemoSkip?: boolean; - hasMemoIntrinsic?: boolean; - hasMemoEntry?: boolean; +export type AstNodeCacheValueMetadata = { + [key in string]?: any; } export class NodeCache { private _isCollected: boolean = false; private cacheMap: Map; - private static instance: NodeCache; - private constructor() { + constructor() { this.cacheMap = new Map(); } - static getInstance(): NodeCache { - if (!this.instance) { - this.instance = new NodeCache(); - } - return this.instance; - } - collect(node: AstNode, metadata?: AstNodeCacheValueMetadata): void { const peer = node.peer; const type = global.generatedEs2panda._AstNodeTypeConst(global.context, node.peer); @@ -101,3 +87,45 @@ export class NodeCache { }); } } + +export class NodeCacheFactory { + private cacheMap: Map; + private static instance: NodeCacheFactory; + + private constructor() { + this.cacheMap = new Map(); + } + + static getInstance(): NodeCacheFactory { + if (!this.instance) { + this.instance = new NodeCacheFactory(); + } + return this.instance; + } + + getCache(key: string): NodeCache { + if (!this.cacheMap.has(key)) { + this.cacheMap.set(key, new NodeCache()); + } + return this.cacheMap.get(key)!; + } + + clear(): void { + this.cacheMap.forEach((cache) => { + cache.clear(); + }); + this.cacheMap = new Map(); + } + + has(node: AstNode): boolean { + return Array.from(this.cacheMap.values()).some((cache) => cache.has(node)); + } + + refresh(original: AstNode, node: AstNode): void { + this.cacheMap.forEach((cache) => { + if (cache.has(original)) { + cache.refresh(original, node); + } + }); + } +} \ No newline at end of file diff --git a/koala-wrapper/src/arkts-api/utilities/public.ts b/koala-wrapper/src/arkts-api/utilities/public.ts index c630d2ac8..b086503e0 100644 --- a/koala-wrapper/src/arkts-api/utilities/public.ts +++ b/koala-wrapper/src/arkts-api/utilities/public.ts @@ -39,7 +39,7 @@ import { type AnnotationUsage, } from '../../generated'; import { Program } from '../peers/Program'; -import { clearNodeCache } from '../class-by-peer'; +import { clearNodeCache } from '../node-by-type'; import { SourcePosition } from '../peers/SourcePosition'; import { MemberExpression } from '../to-be-generated/MemberExpression'; import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; @@ -101,7 +101,7 @@ export function getDecl(node: AstNode): AstNode | undefined { if (isObjectExpression(node)) { return getPeerObjectDecl(passNode(node)); } - const decl = getPeerDecl(passNode(node)); + const decl = getPeerIdentifierDecl(passNode(node)); if (!!decl) { return decl; } @@ -111,12 +111,20 @@ export function getDecl(node: AstNode): AstNode | undefined { return undefined; } +// export function getDecl(node: AstNode): AstNode | undefined { +// const decl = global.es2panda._DeclarationFromAstNode(global.context, node.peer); +// if (decl === nullptr) { +// return undefined; +// } +// return unpackNonNullableNode(decl); +// } + function getDeclFromProperty(node: Property): AstNode | undefined { if (!node.key) { return undefined; } if (!!node.parent && !isObjectExpression(node.parent)) { - return getPeerDecl(passNode(node.key)); + return getPeerIdentifierDecl(passNode(node.key)); } return getDeclFromObjectExpressionProperty(node); } @@ -150,7 +158,7 @@ function getDeclFromArrayOrObjectMember(node: MemberExpression): AstNode | undef return getDecl(node.property); } -export function getPeerDecl(peer: KNativePointer): AstNode | undefined { +export function getPeerIdentifierDecl(peer: KNativePointer): AstNode | undefined { const decl = global.es2panda._DeclarationFromIdentifier(global.context, peer); if (decl === nullptr) { return undefined; @@ -166,6 +174,22 @@ export function getPeerObjectDecl(peer: KNativePointer): AstNode | undefined { return unpackNonNullableNode(decl); } +export function getPeerMemberDecl(peer: KNativePointer): AstNode | undefined { + const decl = global.es2panda._DeclarationFromMemberExpression(global.context, peer); + if (decl === nullptr) { + return undefined; + } + return unpackNonNullableNode(decl); +} + +export function getPeerPropertyDecl(peer: KNativePointer): AstNode | undefined { + const decl = global.es2panda._DeclarationFromProperty(global.context, peer); + if (decl === nullptr) { + return undefined; + } + return unpackNonNullableNode(decl); +} + export function getAnnotations(node: AstNode): readonly AnnotationUsage[] { if (!isFunctionDeclaration(node) && !isScriptFunction(node) && !isClassDefinition(node)) { throwError('for now annotations allowed only for: functionDeclaration, scriptFunction, classDefinition'); @@ -217,8 +241,12 @@ export function importDeclarationInsert(node: ETSImportDeclaration, program: Pro global.es2panda._InsertETSImportDeclarationAndParse(global.context, program.peer, node.peer); } -export function getProgramFromAstNode(node: AstNode): Program { - return new Program(global.es2panda._AstNodeProgram(global.context, node.peer)); +export function getProgramFromAstNode(node: AstNode): Program | undefined { + const programPeer = global.es2panda._AstNodeProgram(global.context, node.peer); + if (programPeer === nullptr) { + return undefined; + } + return new Program(programPeer); } export function hasModifierFlag(node: AstNode, flag: Es2pandaModifierFlags): boolean { diff --git a/koala-wrapper/src/arkts-api/visitor.ts b/koala-wrapper/src/arkts-api/visitor.ts index a08392e69..4c2b6e7e7 100644 --- a/koala-wrapper/src/arkts-api/visitor.ts +++ b/koala-wrapper/src/arkts-api/visitor.ts @@ -56,6 +56,7 @@ import { isETSFunctionType, isSwitchStatement, isSwitchCaseStatement, + isSpreadElement, } from '../generated'; import { isEtsScript, @@ -224,6 +225,10 @@ function visitTrivialExpression(node: AstNode, visitor: Visitor): AstNode { node.operatorType ); } + if (isSpreadElement(node)) { + const nodeType = global.generatedEs2panda._AstNodeTypeConst(global.context, node.peer); + return factory.updateSpreadElement(node, nodeType, nodeVisitor(node.argument, visitor)); + } // TODO return node; } diff --git a/koala-wrapper/src/generated/peers/SpreadElement.ts b/koala-wrapper/src/generated/peers/SpreadElement.ts index 4b721b993..cf966e5ff 100644 --- a/koala-wrapper/src/generated/peers/SpreadElement.ts +++ b/koala-wrapper/src/generated/peers/SpreadElement.ts @@ -22,25 +22,36 @@ import { unpackNodeArray, assertValidPeer, AstNode, - Es2pandaAstNodeType, KNativePointer, nodeByType, ArktsObject, - unpackString + unpackString, + Es2pandaAstNodeType } from "../../reexport-for-generated" import { AnnotatedExpression } from "./AnnotatedExpression" -import { Expression } from "./Expression" import { Decorator } from "./Decorator" -import { ValidationInfo } from "./ValidationInfo" +import { Expression } from "./Expression" import { TypeNode } from "./TypeNode" +import { ValidationInfo } from "./ValidationInfo" + export class SpreadElement extends AnnotatedExpression { - constructor(pointer: KNativePointer) { + constructor(pointer: KNativePointer) { + assertValidPeer(pointer, Es2pandaAstNodeType.AST_NODE_TYPE_SPREAD_ELEMENT) super(pointer) - + } + static createSpreadElement(nodeType: Es2pandaAstNodeType, argument?: Expression): SpreadElement { + const result: SpreadElement = new SpreadElement(global.generatedEs2panda._CreateSpreadElement(global.context, nodeType, passNode(argument))) + result.updateChildren() + return result + } + static updateSpreadElement(original: SpreadElement | undefined, nodeType: Es2pandaAstNodeType, argument?: Expression): SpreadElement { + const result: SpreadElement = new SpreadElement(global.generatedEs2panda._UpdateSpreadElement(global.context, passNode(original), nodeType, passNode(argument))) + result.updateChildren() + return result } get argument(): Expression | undefined { - return unpackNode(global.generatedEs2panda._SpreadElementArgumentConst(global.context, this.peer)) + return unpackNode(global.generatedEs2panda._SpreadElementArgument(global.context, this.peer)) } get isOptional(): boolean { return global.generatedEs2panda._SpreadElementIsOptionalConst(global.context, this.peer) @@ -53,15 +64,22 @@ export class SpreadElement extends AnnotatedExpression { global.generatedEs2panda._SpreadElementSetOptional(global.context, this.peer, optional_arg) return this } + get validateExpression(): ValidationInfo | undefined { + return new ValidationInfo(global.generatedEs2panda._SpreadElementValidateExpression(global.context, this.peer)) + } get typeAnnotation(): TypeNode | undefined { return unpackNode(global.generatedEs2panda._SpreadElementTypeAnnotationConst(global.context, this.peer)) } /** @deprecated */ - setTsTypeAnnotation(typeAnnotation: TypeNode): this { + setTsTypeAnnotation(typeAnnotation?: TypeNode): this { global.generatedEs2panda._SpreadElementSetTsTypeAnnotation(global.context, this.peer, passNode(typeAnnotation)) return this } + protected readonly brandSpreadElement: undefined } -export function isSpreadElement(node: AstNode): node is SpreadElement { +export function isSpreadElement(node: object | undefined): node is SpreadElement { return node instanceof SpreadElement -} \ No newline at end of file +} +if (!nodeByType.has(Es2pandaAstNodeType.AST_NODE_TYPE_SPREAD_ELEMENT)) { + nodeByType.set(Es2pandaAstNodeType.AST_NODE_TYPE_SPREAD_ELEMENT, SpreadElement) +} diff --git a/koala-wrapper/src/reexport-for-generated.ts b/koala-wrapper/src/reexport-for-generated.ts index 37e3c6f56..cefb8764c 100644 --- a/koala-wrapper/src/reexport-for-generated.ts +++ b/koala-wrapper/src/reexport-for-generated.ts @@ -27,6 +27,6 @@ export { unpackObject, assertValidPeer } from "./arkts-api/utilities/private" -export { nodeByType } from "./arkts-api/class-by-peer" +export { nodeByType } from "./arkts-api/node-by-type" export { global } from "./arkts-api/static/global" export { Es2pandaMemberExpressionKind } from "./generated/Es2pandaEnums" -- Gitee