diff --git a/libarkts/src/arkts-api/static/globalUtils.ts b/libarkts/src/arkts-api/static/globalUtils.ts index 8ab8559f2ab43e5ab8f3dddda983695c728d05b3..6dbbff6354da9bb5e28f066e44309050915dea65 100644 --- a/libarkts/src/arkts-api/static/globalUtils.ts +++ b/libarkts/src/arkts-api/static/globalUtils.ts @@ -18,10 +18,13 @@ import { Context } from '../peers/Context'; import { global } from './global'; import { NodeCache } from '../node-cache'; -export function getOrUpdateGlobalContext(peer: KNativePointer): Context { +export function getOrUpdateGlobalContext(peer: KNativePointer, shouldClearCache: boolean = false): Context { if (!global.compilerContext || global.context !== peer) { NodeCache.clear(); global.compilerContext = new Context(peer); } + if (shouldClearCache) { + NodeCache.clear(); + } return global.compilerContext; } diff --git a/libarkts/src/arkts-api/utilities/performance.ts b/libarkts/src/arkts-api/utilities/performance.ts index 065a589c0caf4a8fe3be51849191a0d06a72d9cc..3fc601e3e198228badb1a8374ea9257edca152a7 100644 --- a/libarkts/src/arkts-api/utilities/performance.ts +++ b/libarkts/src/arkts-api/utilities/performance.ts @@ -248,7 +248,8 @@ export class Performance { } clearTotalDuration(): void { - this.totalDuration = 0; + this.detailedEventInfos.clear(); + this.detailedEvents.clear(); this.detailedEventInfos.clear(); this.detailedEvents.clear(); } diff --git a/libarkts/src/memo-node-cache.ts b/libarkts/src/memo-node-cache.ts index dfc304b724026f471555200ca66fbf0d896e6788..57dc8c4f7e73df2360eeb5207b775ef0a9dfbedc 100644 --- a/libarkts/src/memo-node-cache.ts +++ b/libarkts/src/memo-node-cache.ts @@ -42,9 +42,12 @@ export class MemoNodeCache { private cacheMap: Map; private static instance: MemoNodeCache; static disableMemoNodeCache = false; + private _shouldCollectUpdate: boolean = false; + private nodesToUpdate: Set; private constructor() { this.cacheMap = new Map(); + this.nodesToUpdate = new Set(); } static getInstance(): MemoNodeCache { @@ -78,6 +81,9 @@ export class MemoNodeCache { if (MemoNodeCache.disableMemoNodeCache) { return } + if (this._shouldCollectUpdate) { + this._collectNodesToUpdate(node, node.parent); + } const peer = node.peer; const type = global.generatedEs2panda._AstNodeTypeConst(global.context, node.peer); let currMetadata: AstNodeCacheValueMetadata | undefined = metadata ?? {}; @@ -96,6 +102,7 @@ export class MemoNodeCache { metadata = this.get(original)?.metadata; this.cacheMap.delete(original.peer); } + this._collectNodesToUpdate(node); this.collect(node, metadata); } @@ -113,6 +120,7 @@ export class MemoNodeCache { clear(): void { this.cacheMap.clear(); + this.nodesToUpdate.clear(); this._isCollected = false; } @@ -125,6 +133,49 @@ export class MemoNodeCache { ); }); } + + shouldUpdate(node: AstNode): boolean { + if (!this._shouldCollectUpdate) { + return true; + } + return this.nodesToUpdate.has(node.peer); + } + + refreshUpdate(original: AstNode, node: AstNode): void { + if (this.shouldUpdate(original)) { + this.nodesToUpdate.delete(original.peer); + } + this._collectNodesToUpdate(node, original.parent); + } + + shouldUpdateByPeer(peer: KNativePointer): boolean { + if (!this._shouldCollectUpdate) { + return true; + } + return this.nodesToUpdate.has(peer); + } + + addNodeToUpdateByPeer(peer: KNativePointer): void { + if (!this._isCollected && !this._shouldCollectUpdate) { + return; + } + this.nodesToUpdate.add(peer); + } + + shouldCollectUpdate(shouldCollectUpdate: boolean): this { + this._shouldCollectUpdate = shouldCollectUpdate; + return this; + } + + private _collectNodesToUpdate(node: AstNode, parent?: AstNode): void { + this.nodesToUpdate.add(node.peer); + let currParent: AstNode | undefined = parent; + while (!!currParent && !this.nodesToUpdate.has(currParent.peer)) { + this.nodesToUpdate.add(currParent.peer); + currParent = currParent.parent; + } + this._isCollected = true; + } } function wrapFuncWithNodeCache(cache: MemoNodeCache, funcName: keyof typeof factory) { diff --git a/ui2abc/arkui-plugins/collectors/collector.ts b/ui2abc/arkui-plugins/collectors/collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..069788fb525ebb937c5abc0510bf20c631cdce07 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/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 { matchPrefix } from '../common/arkts-utils'; +import { getPerfName } from '../common/debug'; +import { LINTER_EXCLUDE_EXTERNAL_SOURCE_PREFIXES } from '../common/predefines'; +import { LogCollector } from '../common/log-collector'; +import { ImportCollector } from '../common/import-collector'; +import { MetaDataCollector } from '../common/metadata-collector'; +import { ValidatorBuilder } from './ui-collectors/validators'; +import { CallRecordCollector } from './ui-collectors/call-record-collector'; +import { UICollectMetadata } from './ui-collectors/shared-types'; +import { collectUINodeByTypeInPostOrder, collectUINodeByTypeInPreOrder } from './ui-collectors/factory'; +import { collectMemoableNodeByTypeInPostOrder } from './memo-collectors/factory'; + +export interface CollectorOptions extends VisitorOptions { + shouldIgnoreDecl?: boolean; + shouldCollectUI?: boolean; + shouldCollectMemo?: boolean; + shouldCheckUISyntax?: boolean; +} + +export class Collector extends AbstractVisitor { + private _shouldIgnoreDecl?: boolean; + private _shouldCollectUI?: boolean; + private _shouldCollectMemo?: boolean; + private _shouldCheckUISyntax?: boolean; + + constructor(options?: CollectorOptions) { + super(options); + this._shouldIgnoreDecl = options?.shouldIgnoreDecl; + this._shouldCollectUI = options?.shouldCollectUI; + this._shouldCollectMemo = options?.shouldCollectMemo; + this._shouldCheckUISyntax = options?.shouldCheckUISyntax; + } + + get shouldIgnoreDecl(): boolean { + return this._shouldIgnoreDecl ?? false; + } + + get shouldCollectUI(): boolean { + return this._shouldCollectUI ?? false; + } + + get shouldCollectMemo(): boolean { + return this._shouldCollectMemo ?? false; + } + + get shouldCheckUISyntax(): boolean { + if (!this._shouldCheckUISyntax) { + return false; + } + return this.shouldCollectUI; + } + + init(): void { + super.init(); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([0, 0, 1], 'ValidatorBuilder.shouldSkip')); + ValidatorBuilder.shouldSkip = + !!this.shouldCheckUISyntax && !!this.externalSourceName + ? matchPrefix(LINTER_EXCLUDE_EXTERNAL_SOURCE_PREFIXES, this.externalSourceName) + : true; + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([0, 0, 1], 'ValidatorBuilder.shouldSkip')); + MetaDataCollector.getInstance().setExternalSourceName(this.externalSourceName); + } + + reset(): void { + super.reset(); + if (this.shouldCollectUI) { + CallRecordCollector.getInstance(this.getMetadata()).reset(); + } + if (this.shouldCheckUISyntax) { + ValidatorBuilder.reset(); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([0, 0, 2], 'LogCollector.emitLogInfo')); + LogCollector.getInstance().emitLogInfo(); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([0, 0, 2], 'LogCollector.emitLogInfo')); + LogCollector.getInstance().reset(); + } + } + + private getMetadata(): UICollectMetadata { + return { + isExternal: this.isExternal, + externalSourceName: this.externalSourceName, + program: this.program, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }; + } + + private preOrderVisitor(node: arkts.AstNode): arkts.AstNode { + const nodeType = arkts.nodeType(node); + if (this.shouldCollectUI) { + collectUINodeByTypeInPreOrder(nodeType, node, this.getMetadata()); + } + return node; + } + + private postOrderVisitor(node: arkts.AstNode): arkts.AstNode { + const nodeType = arkts.nodeType(node); + if (this.shouldCollectUI) { + collectUINodeByTypeInPostOrder(nodeType, node, this.getMetadata()); + } + if (this.shouldCollectMemo) { + collectMemoableNodeByTypeInPostOrder(nodeType, node); + } + return node; + } + + visitor(node: arkts.AstNode): arkts.AstNode { + this.preOrderVisitor(node); + let newNode = this.visitEachChild(node); + + if (arkts.isETSModule(newNode) && this.shouldCollectMemo) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([0, 0, 3], 'ImportCollector.insertCurrentImports') + ); + if (ImportCollector.getInstance().importInfos.length > 0) { + let imports = ImportCollector.getInstance().getImportStatements(); + newNode = arkts.factory.updateETSModule(newNode, [...imports, ...newNode.statements], newNode.ident, newNode.getNamespaceFlag(), newNode.program); + } + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([0, 0, 3], 'ImportCollector.insertCurrentImports') + ); + ImportCollector.getInstance().clearImports(); + } + this.postOrderVisitor(newNode); + return newNode; + } +} diff --git a/ui2abc/arkui-plugins/collectors/memo-collectors/factory.ts b/ui2abc/arkui-plugins/collectors/memo-collectors/factory.ts index 475911bd988b4516550ae8c3cd6a94a153c5e384..da4890036b3ff88ad24ce6c0ec7edd8f940e8358 100644 --- a/ui2abc/arkui-plugins/collectors/memo-collectors/factory.ts +++ b/ui2abc/arkui-plugins/collectors/memo-collectors/factory.ts @@ -24,8 +24,11 @@ import { findCanAddMemoFromParameter, findCanAddMemoFromProperty, findCanAddMemoFromTypeAlias, + isArrowFunctionAsValue, } from './utils'; -import { coerceToAstNode } from '../../common/arkts-utils'; +import { coerceToAstNode, isDecoratorAnnotation } from '../../common/arkts-utils'; +import { getPerfName } from '../../common/debug'; +import { DecoratorNames } from "../../common/predefines"; export type RewriteAfterFoundFn = ( node: T, @@ -34,16 +37,27 @@ export type RewriteAfterFoundFn = ( export function findAndCollectMemoableNode(node: arkts.AstNode, rewriteFn?: RewriteAfterFoundFn): arkts.AstNode { const type = arkts.nodeType(node); + collectMemoableNodeByTypeInPostOrder(type, node, rewriteFn); + return node; +} + +export function collectMemoableNodeByTypeInPostOrder( + type: arkts.Es2pandaAstNodeType, + node: arkts.AstNode, + rewriteFn?: RewriteAfterFoundFn +): void { if (collectByType.has(type)) { - return collectByType.get(type)!(node, rewriteFn); + const func = collectByType.get(type)!; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([0, 2, 2], func.name)); + func(node, rewriteFn); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([0, 2, 2], func.name)); } - return node; } export class factory { /** * Find and collect possible `@memo` property with arrow function value. - * + * * @param node `arkts.Property` node * @param rewriteFn function callback to rewrite node when it is `@memo` property * @returns `arkts.Property` node @@ -55,7 +69,12 @@ export class factory { let found: boolean = false; if (findCanAddMemoFromProperty(node)) { found = true; - addMemoAnnotation(node.value! as arkts.ArrowFunctionExpression); + const value = node.value!; + if (isArrowFunctionAsValue(value)) { + addMemoAnnotation(value.expr! as arkts.ArrowFunctionExpression); + } else { + addMemoAnnotation(value as arkts.ArrowFunctionExpression); + } } if (found && !!rewriteFn) { return rewriteFn(node, arkts.Es2pandaAstNodeType.AST_NODE_TYPE_PROPERTY); @@ -65,7 +84,7 @@ export class factory { /** * Find and collect possible `@memo` class property with arrow function value. - * + * * @param node `arkts.ClassProperty` node * @param rewriteFn function callback to rewrite node when it is `@memo` class property * @returns `arkts.ClassProperty` node @@ -87,7 +106,7 @@ export class factory { /** * Find and collect possible `@memo` type alias with function type. - * + * * @param node `arkts.TSTypeAliasDeclaration` node * @param rewriteFn function callback to rewrite node when it is `@memo` type alias * @returns `arkts.TSTypeAliasDeclaration` node @@ -109,7 +128,7 @@ export class factory { /** * Find and collect possible `@memo` parameter with function type. - * + * * @param node `arkts.ETSParameterExpression` node * @param rewriteFn function callback to rewrite node when it is `@memo` parameter * @returns `arkts.ETSParameterExpression` node @@ -131,7 +150,7 @@ export class factory { /** * Find and collect possible `@memo` method. - * + * * @param node `arkts.MethodDefinition` node * @param rewriteFn function callback to rewrite node when it is `@memo` method * @returns `arkts.MethodDefinition` node @@ -153,7 +172,7 @@ export class factory { /** * Find and collect possible `@memo` arrow function. - * + * * @param node `arkts.ArrowFunctionExpression` node * @param rewriteFn function callback to rewrite node when it is `@memo` arrow function * @returns `arkts.ArrowFunctionExpression` node @@ -165,7 +184,11 @@ export class factory { let found: boolean = false; if (findCanAddMemoFromArrowFunction(node)) { found = true; - addMemoAnnotation(node.function!); + // TBD(Upgrade): Adding @Memo to arkts.ScriptFunction of lambda leads to segfault + if (!node.annotations.some(it => + isDecoratorAnnotation(it, DecoratorNames.BUILDER))) { + addMemoAnnotation(node.function!); + } } if (found && !!rewriteFn) { return rewriteFn(node, arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION); @@ -175,7 +198,7 @@ export class factory { /** * Find and collect possible `@memo` function call. - * + * * @param node `arkts.CallExpression` node * @returns `arkts.CallExpression` node */ @@ -193,7 +216,7 @@ export class factory { /** * Find and collect new class instance with possible `@memo` type parameters. - * + * * @param node `arkts.ETSNewClassInstanceExpression` node * @returns `arkts.ETSNewClassInstanceExpression` node */ diff --git a/ui2abc/arkui-plugins/collectors/memo-collectors/function-collector.ts b/ui2abc/arkui-plugins/collectors/memo-collectors/function-collector.ts index 4b66f6e195fd2c8d9d8236dfc444acad2a11be6d..be96ec489cd265d6fc46860d5826e8d8761fe360 100644 --- a/ui2abc/arkui-plugins/collectors/memo-collectors/function-collector.ts +++ b/ui2abc/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, @@ -27,6 +28,8 @@ import { getDeclResolveAlias, MemoableInfo, } from './utils'; +import { NodeCacheFactory } from '../../common/node-cache'; + export class MemoFunctionCollector extends AbstractVisitor { private returnMemoableInfo: MemoableInfo | undefined; private paramMemoableInfoMap: Map | undefined; @@ -56,14 +59,14 @@ export class MemoFunctionCollector extends AbstractVisitor { private collectMemoAstNode(node: arkts.AstNode, info: MemoableInfo): void { if (checkIsMemoFromMemoableInfo(info, false)) { - arkts.MemoNodeCache.getInstance().collect(node); + 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.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } @@ -72,10 +75,11 @@ export class MemoFunctionCollector extends AbstractVisitor { declarator: arkts.VariableDeclarator ): void { const shouldCollect = - arkts.MemoNodeCache.getInstance().has(declarator) || - (!!declarator.init && arkts.MemoNodeCache.getInstance().has(declarator.init)); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(declarator) || + (!!declarator.init && + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(declarator.init)); if (shouldCollect) { - arkts.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } @@ -93,15 +97,15 @@ export class MemoFunctionCollector extends AbstractVisitor { if (arkts.isArrowFunctionExpression(node.init)) { const func = node.init.function!; const localInfo = collectMemoableInfoInScriptFunction(func); - const shouldCollectParameter = - (localInfo.hasBuilder || localInfo.hasMemo) && !localInfo.hasMemoEntry && !localInfo.hasMemoIntrinsic; - const shouldCollectReturn = - localInfo.hasBuilder || localInfo.hasMemo || memoableInfo.hasBuilder || memoableInfo.hasMemo; + const hasMemo = + checkIsMemoFromMemoableInfo(memoableInfo, false) || localInfo.hasBuilder || localInfo.hasMemo; + const shouldCollectParameter = hasMemo && !localInfo.hasMemoEntry && !localInfo.hasMemoIntrinsic; + const shouldCollectReturn = hasMemo; const returnMemoableInfo = collectMemoableInfoInFunctionReturnType(func); collectScriptFunctionReturnTypeFromInfo(func, returnMemoableInfo); const [paramMemoableInfoMap, gensymCount] = collectMemoableInfoMapInFunctionParams( func, - shouldCollectParameter + !!shouldCollectParameter ); const body = func.body; if (!!body && arkts.isBlockStatement(body)) { @@ -121,7 +125,7 @@ export class MemoFunctionCollector extends AbstractVisitor { } private visitCallExpression(node: arkts.CallExpression): arkts.AstNode { - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { this.disableCollectReturnBeforeCallback(() => { this.visitEachChild(node); }); @@ -135,8 +139,8 @@ export class MemoFunctionCollector extends AbstractVisitor { }); return node; } - if (arkts.MemoNodeCache.getInstance().has(decl)) { - arkts.MemoNodeCache.getInstance().collect(node); + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } if (this.paramMemoableInfoMap?.has(decl.peer)) { this.collectCallWithDeclaredPeerInParamMap(node, decl.peer); @@ -156,10 +160,14 @@ export class MemoFunctionCollector extends AbstractVisitor { if (!decl) { return node; } + let memoableInfo: MemoableInfo | undefined; if (this.paramMemoableInfoMap?.has(decl.peer)) { - arkts.MemoNodeCache.getInstance().collect(node); + memoableInfo = this.paramMemoableInfoMap.get(decl.peer); } else if (arkts.isETSParameterExpression(decl) && this.paramMemoableInfoMap?.has(decl.ident!.peer)) { - arkts.MemoNodeCache.getInstance().collect(node); + memoableInfo = this.paramMemoableInfoMap.get(decl.ident!.peer); + } + if (!!memoableInfo) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } return node; } @@ -168,7 +176,7 @@ export class MemoFunctionCollector extends AbstractVisitor { if (!!this.returnMemoableInfo && !!node.argument && arkts.isArrowFunctionExpression(node.argument)) { this.collectMemoAstNode(node.argument, this.returnMemoableInfo); } - arkts.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); this.visitEachChild(node); return node; } @@ -215,8 +223,8 @@ export class MemoFunctionCollector extends AbstractVisitor { } if ( arkts.isArrowFunctionExpression(node) && - !arkts.MemoNodeCache.getInstance().has(node) && - !arkts.MemoNodeCache.getInstance().has(node.function!) + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) && + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node.function) ) { this.shouldCollectReturn = false; } diff --git a/ui2abc/arkui-plugins/collectors/memo-collectors/utils.ts b/ui2abc/arkui-plugins/collectors/memo-collectors/utils.ts index 82c9876be13f5e84dc7a320ed8dcd63082e80dc6..518504173567a62faf0dc72a53a849091d194d2a 100644 --- a/ui2abc/arkui-plugins/collectors/memo-collectors/utils.ts +++ b/ui2abc/arkui-plugins/collectors/memo-collectors/utils.ts @@ -14,12 +14,20 @@ */ import * as arkts from '@koalaui/libarkts'; -import { ImportCollector } from '../../common/import-collector'; import { annotation, forEachArgWithParam, isDecoratorAnnotation } from '../../common/arkts-utils'; -import { DecoratorNames, GenSymPrefix, MEMO_IMPORT_SOURCE_NAME, MEMO_SKIP_UI_IMPORT_SOURCE_NAME } from '../../common/predefines'; +import { ImportCollector } from '../../common/import-collector'; +import { + DecoratorNames, + BuiltInNames, + MEMO_IMPORT_SOURCE_NAME, + NodeCacheNames, + MEMO_SKIP_UI_IMPORT_SOURCE_NAME, +} from '../../common/predefines'; import { AstNodeRevisitCache } from '../../common/cache/astNodeRevisitCache'; +import { AstNodePointer } from '../../common/safe-types'; import { MemoFunctionCollector } from './function-collector'; -import { disableMemoNodeCache } from '../../common/use-improved-memo-plugin'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; +import { disableMemoNodeCache } from "../../common/use-improved-memo-plugin"; export enum MemoNames { MEMO = 'memo', @@ -27,6 +35,7 @@ export enum MemoNames { MEMO_SKIP_UI = 'MemoSkip', MEMO_INTRINSIC = 'memo_intrinsic', MEMO_ENTRY = 'memo_entry', + MEMO_UI = 'Memo', MEMO_STABLE = 'memo_stable', } @@ -67,7 +76,9 @@ export function isMemoAnnotation(node: arkts.AnnotationUsage, memoName: MemoName } export function hasMemoAnnotation(node: T): boolean { - return node.annotations.some((it) => isMemoAnnotation(it, MemoNames.MEMO)); + return node.annotations.some( + (it) => isMemoAnnotation(it, MemoNames.MEMO) || isMemoAnnotation(it, MemoNames.MEMO_UI) + ); } function insertMemoAnnotationImport(memoName: MemoNames): void { @@ -80,8 +91,9 @@ function isScriptFunctionFromInterfaceGetterSetter(node: arkts.ScriptFunction): if (!methodDef || !arkts.isMethodDefinition(methodDef)) { return false; } - const isGetterSetter = methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET - || methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET; + const isGetterSetter = + methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET || + methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET; if (!isGetterSetter) { return false; } @@ -94,7 +106,7 @@ function isScriptFunctionFromInterfaceGetterSetter(node: arkts.ScriptFunction): function addMemoAnnotationInScriptFunction( node: arkts.ScriptFunction, - memoName: MemoNames = MemoNames.MEMO, + memoName: MemoNames = MemoNames.MEMO_UI, skipNames: MemoNames[] = [MemoNames.MEMO_SKIP, MemoNames.MEMO_SKIP_UI] ): arkts.ScriptFunction { const newAnnotations: arkts.AnnotationUsage[] = [ @@ -112,7 +124,7 @@ function addMemoAnnotationInScriptFunction( function addMemoAnnotationInUnionType( node: arkts.ETSUnionType, - memoName: MemoNames = MemoNames.MEMO, + memoName: MemoNames = MemoNames.MEMO_UI, skipNames: MemoNames[] = [MemoNames.MEMO_SKIP, MemoNames.MEMO_SKIP_UI] ): arkts.ETSUnionType { return arkts.factory.updateETSUnionType( @@ -128,17 +140,17 @@ function addMemoAnnotationInUnionType( function collectMemoAstNode( node: arkts.AstNode, - memoName: MemoNames = MemoNames.MEMO, + memoName: MemoNames = MemoNames.MEMO_UI, skipNames: MemoNames[] = [MemoNames.MEMO_SKIP, MemoNames.MEMO_SKIP_UI] ): void { if (!skipNames.includes(memoName)) { - arkts.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } } export function addMemoAnnotation( node: T, - memoName: MemoNames = MemoNames.MEMO, + memoName: MemoNames = MemoNames.MEMO_UI, skipNames: MemoNames[] = [MemoNames.MEMO_SKIP, MemoNames.MEMO_SKIP_UI] ): T { insertMemoAnnotationImport(memoName); @@ -152,7 +164,6 @@ export function addMemoAnnotation( ...node.annotations.filter((it) => !isMemoAnnotation(it, memoName)), annotation(memoName), ]; - collectMemoAnnotationImport(memoName); if (arkts.isETSParameterExpression(node)) { node.setAnnotations(newAnnotations); collectMemoAstNode(node, memoName, skipNames); @@ -172,9 +183,9 @@ export function hasMemoableAnnotation(node: T): MemoableA let hasMemoEntry: boolean = false; node.annotations.forEach((it) => { hasBuilder ||= isDecoratorAnnotation(it, DecoratorNames.BUILDER); - hasBuilder ||= isDecoratorAnnotation(it, DecoratorNames.LOCAL_BUILDER); + hasBuilder ||= isDecoratorAnnotation(it, DecoratorNames.LOCAL_BUILDER) hasBuilderParam ||= isDecoratorAnnotation(it, DecoratorNames.BUILDER_PARAM); - hasMemo ||= isMemoAnnotation(it, MemoNames.MEMO); + hasMemo ||= isMemoAnnotation(it, MemoNames.MEMO) || isMemoAnnotation(it, MemoNames.MEMO_UI); hasMemoSkip ||= isMemoAnnotation(it, MemoNames.MEMO_SKIP); hasMemoIntrinsic ||= isMemoAnnotation(it, MemoNames.MEMO_INTRINSIC); hasMemoEntry ||= isMemoAnnotation(it, MemoNames.MEMO_ENTRY); @@ -194,7 +205,7 @@ export function collectMemoAnnotationImport(memoName: MemoNames = MemoNames.MEMO } export function collectMemoAnnotationSource(memoName: MemoNames = MemoNames.MEMO): void { - if (memoName == MemoNames.MEMO_SKIP_UI) { + if (memoName === MemoNames.MEMO_SKIP_UI || memoName === MemoNames.MEMO_UI) { ImportCollector.getInstance().collectSource(memoName, MEMO_SKIP_UI_IMPORT_SOURCE_NAME); } else { ImportCollector.getInstance().collectSource(memoName, MEMO_IMPORT_SOURCE_NAME); @@ -203,7 +214,7 @@ export function collectMemoAnnotationSource(memoName: MemoNames = MemoNames.MEMO export function collectMemoableInfoInUnionType(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isETSUnionType(node)) { @@ -247,8 +258,8 @@ function collectMemoableInfoInTypeReferencePart(node: arkts.ETSTypeReferencePart export function collectMemoableInfoInTypeReference(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { - const metadata = arkts.MemoNodeCache.getInstance().get(node)?.metadata; + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { + const metadata = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(node)?.metadata; return { ...currInfo, ...metadata }; } if (!arkts.isETSTypeReference(node) || !node.part || !arkts.isETSTypeReferencePart(node.part)) { @@ -260,7 +271,7 @@ export function collectMemoableInfoInTypeReference(node: arkts.AstNode, info?: M }; const expr = node.part.name; let decl: arkts.AstNode | undefined; - if (!expr || !(decl = arkts.getDecl(expr))) { + if (!expr || !(decl = arkts.getPeerIdentifierDecl(expr.peer))) { return currInfo; } return { @@ -271,7 +282,7 @@ export function collectMemoableInfoInTypeReference(node: arkts.AstNode, info?: M export function collectMemoableInfoInFunctionType(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isETSFunctionType(node)) { @@ -284,11 +295,7 @@ export function collectMemoableInfoInFunctionType(node: arkts.AstNode, info?: Me export function collectMemoableInfoInTypeAlias(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (AstNodeRevisitCache.getInstance().has(node)) { - return currInfo; - } - AstNodeRevisitCache.getInstance().collect(node); - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isTSTypeAliasDeclaration(node)) { @@ -309,8 +316,8 @@ export function collectMemoableInfoInTypeAlias(node: arkts.AstNode, info?: Memoa export function collectMemoableInfoInParameter(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { - const metadata = arkts.MemoNodeCache.getInstance().get(node)?.metadata; + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { + const metadata = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(node)?.metadata; return { ...currInfo, hasMemo: true, hasProperType: true, ...metadata }; } if (!arkts.isETSParameterExpression(node)) { @@ -334,14 +341,16 @@ export function collectMemoableInfoInParameter(node: arkts.AstNode, info?: Memoa } if (!!currInfo.isWithinTypeParams) { const forbidTypeRewrite = !checkIsMemoFromMemoableInfo(currInfo); - arkts.MemoNodeCache.getInstance().collect(node, { forbidTypeRewrite, isWithinTypeParams: true }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { forbidTypeRewrite, isWithinTypeParams: true }); } return currInfo; } export function collectMemoableInfoInVariableDeclarator(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isVariableDeclarator(node)) { @@ -365,7 +374,7 @@ export function collectMemoableInfoInVariableDeclarator(node: arkts.AstNode, inf ...hasMemoableAnnotation(node.parent), }; } - const decl = arkts.getDecl(node.id!); + const decl = arkts.getPeerIdentifierDecl(node.id!.peer); if (!decl) { return currInfo; } @@ -385,7 +394,7 @@ export function collectMemoableInfoInVariableDeclarator(node: arkts.AstNode, inf export function collectMemoableInfoInProperty(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (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 }; @@ -393,7 +402,7 @@ export function collectMemoableInfoInProperty(node: arkts.AstNode, info?: Memoab if (!arkts.isProperty(node) || !node.key || !arkts.isIdentifier(node.key)) { return currInfo; } - const decl = arkts.getDecl(node.key); + const decl = arkts.getPeerPropertyDecl(node.peer); if (!decl) { return currInfo; } @@ -405,19 +414,21 @@ export function collectMemoableInfoInProperty(node: arkts.AstNode, info?: Memoab currInfo = { ...currInfo, ...newInfo }; } currInfo.hasProperType = false; - if (!!node.value && arkts.isArrowFunctionExpression(node.value)) { - currInfo.hasProperType = true; - currInfo = { - ...currInfo, - ...collectMemoableInfoInScriptFunction(node.value.function!), - }; + const value: arkts.Expression | undefined = node.value; + if (!value) { + return currInfo; } + currInfo.hasProperType = arkts.isArrowFunctionExpression(value) || isArrowFunctionAsValue(value); return currInfo; } +export function isArrowFunctionAsValue(value: arkts.Expression): value is arkts.TSAsExpression { + return arkts.isTSAsExpression(value) && !!value.expr && arkts.isArrowFunctionExpression(value.expr); +} + export function collectMemoableInfoInClassProperty(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isClassProperty(node)) { @@ -441,7 +452,7 @@ export function collectMemoableInfoInClassProperty(node: arkts.AstNode, info?: M export function collectMemoableInfoInArrowFunction(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isArrowFunctionExpression(node)) { @@ -457,7 +468,7 @@ export function collectMemoableInfoInArrowFunction(node: arkts.AstNode, info?: M } if (!!node.parent && arkts.isAssignmentExpression(node.parent) && !!node.parent.left) { const expr = arkts.isMemberExpression(node.parent.left) ? node.parent.left.property : node.parent.left; - const decl = arkts.getDecl(expr!); + const decl = arkts.getPeerIdentifierDecl(expr!.peer); if (!decl) { return currInfo; } @@ -473,7 +484,7 @@ export function collectMemoableInfoInArrowFunction(node: arkts.AstNode, info?: M export function collectMemoableInfoInScriptFunction(node: arkts.AstNode, info?: MemoableInfo): MemoableInfo { let currInfo = info ?? {}; - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return { ...currInfo, hasMemo: true, hasProperType: true }; } if (!arkts.isScriptFunction(node)) { @@ -514,13 +525,17 @@ export function collectMemoableInfoInType(node: arkts.AstNode, info?: MemoableIn export function collectMemoableInfoInFunctionReturnType(node: arkts.ScriptFunction): MemoableInfo { if (!!node.returnTypeAnnotation) { let memoableInfo: MemoableInfo; - if (arkts.MemoNodeCache.getInstance().has(node.returnTypeAnnotation)) { + if (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.MemoNodeCache.getInstance().collect(node.returnTypeAnnotation); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node.returnTypeAnnotation); + } else if (!!memoableInfo.isWithinTypeParams) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { forbidTypeRewrite: true, isWithinTypeParams: true }); } return memoableInfo; } @@ -529,14 +544,16 @@ export function collectMemoableInfoInFunctionReturnType(node: arkts.ScriptFuncti export function collectScriptFunctionReturnTypeFromInfo(node: arkts.ScriptFunction, info: MemoableInfo): void { const returnType = node.returnTypeAnnotation; - if (!returnType || arkts.MemoNodeCache.getInstance().has(returnType)) { + if (!returnType || NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(returnType)) { return; } const isMemoReturnType = checkIsMemoFromMemoableInfo(info); const isWithinTypeParams = info.isWithinTypeParams; if (isMemoReturnType || isWithinTypeParams) { const forbidTypeRewrite = !isMemoReturnType; - arkts.MemoNodeCache.getInstance().collect(returnType, { forbidTypeRewrite, isWithinTypeParams }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(returnType, { forbidTypeRewrite, isWithinTypeParams }); } } @@ -544,7 +561,7 @@ export function collectGensymDeclarator(declarator: arkts.VariableDeclarator, in if (!info.hasMemo && !info.hasBuilder) { return; } - arkts.MemoNodeCache.getInstance().collect(declarator); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(declarator); const initializer = declarator.init; if (!initializer || !arkts.isConditionalExpression(initializer)) { return; @@ -575,9 +592,9 @@ export function collectMemoableInfoMapInFunctionParams( node: arkts.ScriptFunction, shouldCollectParameter: boolean = true, shouldEnforceMemoSkip: boolean = false -): [Map, number] { +): [Map, number] { const hasReceiver = node.hasReceiver; - const paramMap: Map = new Map(); + const paramMap: Map = new Map(); let gensymCount: number = 0; node.params.slice(hasReceiver ? 1 : 0).forEach((p) => { const info = collectMemoableInfoInFunctionParam( @@ -594,7 +611,7 @@ export function collectMemoableInfoMapInFunctionParams( } interface FunctionParamCollectInfo { - peers: arkts.AstNode['peer'][]; + peers: AstNodePointer[]; gensymCount: number; memoableInfo: MemoableInfo; } @@ -606,11 +623,11 @@ function collectMemoableInfoInFunctionParam( shouldCollectParameter: boolean = true, shouldEnforceMemoSkip: boolean = false ): FunctionParamCollectInfo { - const peers: arkts.AstNode['peer'][] = []; + const peers: AstNodePointer[] = []; let memoableInfo: MemoableInfo; const _param = param as arkts.ETSParameterExpression; - if (arkts.MemoNodeCache.getInstance().has(_param)) { - const metadata = arkts.MemoNodeCache.getInstance().get(_param)!.metadata ?? {}; + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(_param)) { + const metadata = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(_param)!.metadata ?? {}; const { hasMemoSkip } = metadata; memoableInfo = { hasMemo: true, hasMemoSkip, hasProperType: true }; } else { @@ -619,7 +636,11 @@ function collectMemoableInfoInFunctionParam( if (shouldEnforceMemoSkip) { memoableInfo.hasMemoSkip = true; } - if (_param.ident!.name.startsWith(GenSymPrefix.INTRINSIC) && !!node.body && arkts.isBlockStatement(node.body)) { + if ( + _param.ident!.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]; @@ -631,7 +652,9 @@ function collectMemoableInfoInFunctionParam( } } if (checkIsMemoFromMemoableInfo(memoableInfo)) { - arkts.MemoNodeCache.getInstance().collect(_param, { hasMemoSkip: memoableInfo.hasMemoSkip }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(_param, { hasMemoSkip: memoableInfo.hasMemoSkip }); } if (!memoableInfo.hasMemoSkip && shouldCollectParameter) { peers.push(_param.ident!.peer); @@ -654,7 +677,7 @@ export function findCanAddMemoFromTypeAnnotation( AstNodeRevisitCache.getInstance().reset(); const memoableInfo = collectMemoableInfoInType(typeAnnotation); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.MemoNodeCache.getInstance().collect(typeAnnotation); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(typeAnnotation); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -669,7 +692,7 @@ export function findCanAddMemoFromProperty(property: arkts.AstNode): property is AstNodeRevisitCache.getInstance().reset(); const memoableInfo = collectMemoableInfoInProperty(property); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.MemoNodeCache.getInstance().collect(property); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(property); } const hasBuilder = !!memoableInfo.hasBuilder || !!memoableInfo.hasBuilderParam; return hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; @@ -685,11 +708,13 @@ export function findCanAddMemoFromClassProperty(property: arkts.AstNode): proper AstNodeRevisitCache.getInstance().reset(); const memoableInfo = collectMemoableInfoInClassProperty(property); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.MemoNodeCache.getInstance().collect(property); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(property); } const hasBuilderType = !!memoableInfo.hasBuilder || !!memoableInfo.hasBuilderParam; if (!!memoableInfo.isWithinTypeParams) { - arkts.MemoNodeCache.getInstance().collect(property, { isWithinTypeParams: true }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(property, { isWithinTypeParams: true }); } return hasBuilderType && !memoableInfo.hasMemo && !!memoableInfo.hasProperType && !memoableInfo.isWithinTypeParams; } @@ -707,7 +732,9 @@ export function findCanAddMemoFromParameter(param: arkts.AstNode | undefined): p AstNodeRevisitCache.getInstance().reset(); const memoableInfo = collectMemoableInfoInParameter(param); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.MemoNodeCache.getInstance().collect(param, { hasMemoSkip: memoableInfo.hasMemoSkip }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(param, { hasMemoSkip: memoableInfo.hasMemoSkip }); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -733,8 +760,10 @@ export function findCanAddMemoFromArrowFunction(node: arkts.AstNode): node is ar !hasMemoEntry && !hasMemoIntrinsic ); const isMemo = checkIsMemoFromMemoableInfo(memoableInfo); - if (isMemo && !arkts.MemoNodeCache.getInstance().has(node)) { - arkts.MemoNodeCache.getInstance().collect(node, { hasMemoEntry, hasMemoIntrinsic }); + if (isMemo && !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasMemoEntry, hasMemoIntrinsic }); const body = func.body; if (!!body && arkts.isBlockStatement(body)) { const disableCollectReturn = hasMemoEntry || hasMemoIntrinsic; @@ -760,7 +789,7 @@ export function findCanAddMemoFromTypeAlias(node: arkts.AstNode): node is arkts. AstNodeRevisitCache.getInstance().reset(); const memoableInfo = collectMemoableInfoInTypeAlias(node); if (!!memoableInfo.hasMemo && !!memoableInfo.hasProperType) { - arkts.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); } return !!memoableInfo.hasBuilder && !memoableInfo.hasMemo && !!memoableInfo.hasProperType; } @@ -788,13 +817,24 @@ export function findCanAddMemoFromMethod(node: arkts.AstNode): node is arkts.Met shouldEnforceMemoSkip ); const isMemo = checkIsMemoFromMemoableInfo(memoableInfo); - if (isMemo && !arkts.MemoNodeCache.getInstance().has(node)) { + if (isMemo && !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { const metadata = collectMetadataInMethod(node); - arkts.MemoNodeCache.getInstance().collect(node, { - ...metadata, - hasMemoEntry, - hasMemoIntrinsic, - }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { + ...metadata, + hasMemoEntry, + hasMemoIntrinsic, + }); + if (metadata.isGetter && returnMemoableInfo.isWithinTypeParams) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(func, { + ...metadata, + hasMemoEntry, + hasMemoIntrinsic, + }); + } const body = func.body; if (!!body && arkts.isBlockStatement(body) && !isScriptFunctionFromInterfaceGetterSetter(func)) { const disableCollectReturn = hasMemoEntry || hasMemoIntrinsic; @@ -819,7 +859,7 @@ export function collectMemoFromTSTypeParameterInstantiation(node: arkts.TSTypePa node.params.forEach((t) => { const typeInfo = collectMemoableInfoInType(t); if (checkIsMemoFromMemoableInfo(typeInfo)) { - arkts.MemoNodeCache.getInstance().collect(t); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(t); } }); } @@ -836,7 +876,9 @@ export function collectMemoFromNewClass(node: arkts.ETSNewClassInstanceExpressio } const typeInfo = collectMemoableInfoInTypeReference(typeRef); if (typeInfo.isWithinTypeParams) { - arkts.MemoNodeCache.getInstance().collect(typeRef, { isWithinTypeParams: true }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(typeRef, { isWithinTypeParams: true }); } } @@ -847,7 +889,7 @@ export function collectMemoFromNewClass(node: arkts.ETSNewClassInstanceExpressio * @param node `arkts.CallExpression` node. */ export function collectMemoFromCallExpression(node: arkts.CallExpression): boolean { - if (arkts.MemoNodeCache.getInstance().has(node)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return false; } const typeParams = node.typeParams; @@ -860,8 +902,8 @@ export function collectMemoFromCallExpression(node: arkts.CallExpression): boole return false; } let isCollected: boolean = false; - if (arkts.MemoNodeCache.getInstance().has(decl)) { - arkts.MemoNodeCache.getInstance().collect(node); + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); isCollected = true; } if (arkts.isMethodDefinition(decl)) { @@ -870,19 +912,19 @@ export function collectMemoFromCallExpression(node: arkts.CallExpression): boole isCollected = collectCallWithDeclaredClassProperty(node, decl); } if (isCollected && arkts.isTSAsExpression(node.callee) && node.callee.typeAnnotation) { - arkts.MemoNodeCache.getInstance().collect(node.callee.typeAnnotation); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node.callee.typeAnnotation); } return isCollected; } export function collectCallWithDeclaredClassProperty(node: arkts.CallExpression, decl: arkts.ClassProperty): boolean { - if (arkts.MemoNodeCache.getInstance().has(decl)) { - arkts.MemoNodeCache.getInstance().collect(node); + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); return true; } const memoableInfo = collectMemoableInfoInClassProperty(decl); if (checkIsMemoFromMemoableInfo(memoableInfo, false) || memoableInfo.hasBuilder || memoableInfo.hasBuilderParam) { - arkts.MemoNodeCache.getInstance().collect(node); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); return true; } return false; @@ -896,15 +938,20 @@ export function collectCallWithDeclaredMethod(node: arkts.CallExpression, decl: const isTrailingCall = node.isTrailingCall; const options = { hasRestParameter, isTrailingCall }; forEachArgWithParam(args, params, collectCallArgsWithMethodParams, options); - if (arkts.MemoNodeCache.getInstance().has(decl)) { - const { hasMemoEntry, hasMemoIntrinsic } = arkts.MemoNodeCache.getInstance().get(decl)!.metadata ?? {}; - arkts.MemoNodeCache.getInstance().collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(decl)) { + const { hasMemoEntry, hasMemoIntrinsic } = + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(decl)!.metadata ?? {}; + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); return true; } else { const memoableInfo = collectMemoableInfoInScriptFunction(decl.function!); if (checkIsMemoFromMemoableInfo(memoableInfo, true)) { const { hasMemoEntry, hasMemoIntrinsic } = memoableInfo; - arkts.MemoNodeCache.getInstance().collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .collect(node, { hasReceiver, hasMemoEntry, hasMemoIntrinsic }); return true; } } @@ -916,14 +963,14 @@ export function collectCallArgsWithMethodParams(arg: arkts.Expression | undefine return; } let info: MemoableInfo; - if (arkts.MemoNodeCache.getInstance().has(param)) { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(param)) { info = { hasMemo: true, hasProperType: true }; } else { info = collectMemoableInfoInParameter(param); } if (checkIsMemoFromMemoableInfo(info) && arkts.isArrowFunctionExpression(arg)) { - arkts.MemoNodeCache.getInstance().collect(arg); - const func = arg.function!; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(arg); + const func = arg.function; const returnMemoableInfo = collectMemoableInfoInFunctionReturnType(func); collectScriptFunctionReturnTypeFromInfo(func, returnMemoableInfo); const [paramMemoableInfoMap, gensymCount] = collectMemoableInfoMapInFunctionParams(func); @@ -956,7 +1003,7 @@ export function findIdentifierFromCallee(callee: arkts.AstNode | undefined): ark export function collectMemoScriptFunctionBody( body: arkts.BlockStatement, returnMemoableInfo: MemoableInfo, - paramMemoableInfoMap: Map, + paramMemoableInfoMap: Map, gensymCount: number, disableCollectReturn?: boolean ): void { @@ -976,24 +1023,6 @@ export function collectMemoScriptFunctionBody( }); } -export interface AstMemoNodeCacheValue { - peer: arkts.KNativePointer; - type: arkts.Es2pandaAstNodeType; - metadata?: AstNodeCacheValueMetadata; -} - -export interface AstNodeCacheValueMetadata { - callName?: string; - hasReceiver?: boolean; - isSetter?: boolean; - isGetter?: boolean; - forbidTypeRewrite?: boolean; - isWithinTypeParams?: boolean; - hasMemoSkip?: boolean; - hasMemoIntrinsic?: boolean; - hasMemoEntry?: boolean; -} - export function collectMetadataInMethod(node: arkts.MethodDefinition): AstNodeCacheValueMetadata { const callName = node.id!.name; const hasReceiver = node.function!.hasReceiver; @@ -1010,7 +1039,12 @@ export function checkIsMemoFromMemoableInfo(info: MemoableInfo, ignoreType: bool } export function getDeclResolveAlias(node: arkts.AstNode): arkts.AstNode | undefined { - const decl = arkts.getDecl(node); + let decl: arkts.AstNode | undefined; + if (!!node.parent && arkts.isProperty(node.parent)) { + decl = arkts.getPeerPropertyDecl(node.parent.peer); + } else { + decl = arkts.getPeerIdentifierDecl(node.peer); + } if (!!decl && !!decl.parent && arkts.isIdentifier(decl) && arkts.isVariableDeclarator(decl.parent)) { if (!!decl.parent.init && arkts.isIdentifier(decl.parent.init)) { return getDeclResolveAlias(decl.parent.init); @@ -1021,22 +1055,3 @@ export function getDeclResolveAlias(node: arkts.AstNode): arkts.AstNode | undefi } return decl; } - -export function parametersBlockHasReceiver(params: readonly arkts.Expression[]): boolean { - return params.length > 0 && arkts.isETSParameterExpression(params[0]) && isThisParam(params[0]); -} - -export function parametrizedNodeHasReceiver(node: arkts.ScriptFunction | arkts.ETSFunctionType | undefined): boolean { - if (node === undefined) { - return false; - } - return parametersBlockHasReceiver(node.params); -} - -function isThisParam(node: arkts.Expression | undefined): boolean { - if (node === undefined || !arkts.isETSParameterExpression(node)) { - return false; - } - return node.ident?.isReceiver ?? false; -} - diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/call-record-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/call-record-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..729a18073af4318115ad29da8a5362bc47f778b1 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/call-record-collector.ts @@ -0,0 +1,203 @@ +/* + * 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 { CallRecordInfo, UICollectMetadata } from './shared-types'; +import { + checkIsCallFromLegacyBuilderFromInfo, + checkIsCustomComponentFromInfo, + checkIsInteropComponentCallFromInfo, + findRootCallee, + findRootCallObject, +} from './utils'; +import { CallValidator, ValidatorBuilder } from './validators'; +import { NodeCacheNames } from '../../common/predefines'; +import { AstNodePointer } from '../../common/safe-types'; +import { ChainingCallDataSource } from './chaining-call-data-source'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export class CallRecordCollector { + private static instance: CallRecordCollector; + private _metadata: UICollectMetadata; + private _prevCallInfo?: CallRecordInfo; + private _chainingCallData: ChainingCallDataSource; + private _inChainCalls: Set; + + public externalSourceName: string | undefined; + + private constructor(metadata: UICollectMetadata) { + this._metadata = metadata; + this._inChainCalls = new Set(); + this._chainingCallData = ChainingCallDataSource.getInstance(); + } + + static getInstance(metadata: UICollectMetadata): CallRecordCollector { + if (!this.instance) { + this.instance = new CallRecordCollector(metadata); + } + return this.instance; + } + + get lastCallInfo(): CallRecordInfo | undefined { + return this._prevCallInfo; + } + + get chainingCallData(): ChainingCallDataSource { + return this._chainingCallData; + } + + private canCollectLegacyCallFromInfo(info: CallInfo): boolean { + const rootCallInfo = info; + if (checkIsCallFromLegacyBuilderFromInfo(rootCallInfo)) { + return true; + } + if (checkIsInteropComponentCallFromInfo(rootCallInfo)) { + return true; + } + return false; + } + + private canCollectCallFromInfo(info: CallInfo): boolean { + const rootCallInfo = info; + if (!!rootCallInfo.isDeclFromLegacy) { + return this.canCollectLegacyCallFromInfo(rootCallInfo); + } + if (!!rootCallInfo.annotationInfo?.hasComponentBuilder || !!rootCallInfo.annotationInfo?.hasBuilder) { + return true; + } + if (!!rootCallInfo.isResourceCall || !!rootCallInfo.isBindableCall) { + return true; + } + if (!!rootCallInfo.structDeclInfo && checkIsCustomComponentFromInfo(rootCallInfo.structDeclInfo)) { + return true; + } + return false; + } + + withExternalSourceName(externalSourceName: string | undefined): this { + this.externalSourceName = externalSourceName; + return this; + } + + reset(): void { + this._prevCallInfo = undefined; + this._chainingCallData.reset(); + this._inChainCalls.clear(); + } + + collect(call: arkts.CallExpression, isFromChainCall?: boolean): void { + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).has(call)) { + return; + } + if (this._inChainCalls.has(call.peer)) { + this._inChainCalls.delete(call.peer); + return; + } + if (!!isFromChainCall) { + this._inChainCalls.add(call.peer); + } + const callRecord = new CallRecord(this._metadata); + // collect external information from current call. + const rootCallObject = findRootCallObject(call.callee); + const rootCallee = findRootCallee(call.callee); + callRecord.withRootCallObject(rootCallObject).withRootCallee(rootCallee); + if (this._chainingCallData.isWithInChain()) { + callRecord.withRootCallInfo(this._chainingCallData.rootCallInfo!.callRecord.toRecord()!); + callRecord.withChainingCallInfos(this._chainingCallData.chainingCallInfos); + } + // collect internal information from current call. + callRecord.collect(call); + const callInfo = callRecord.toRecord(); + if (!callInfo) { + return; + } + this._prevCallInfo = { call, callRecord }; + this._chainingCallData + .setRootCallInfo({ call, callRecord }) + .addChainingCallInfo(call, callRecord.toChainJSON()); + if (this.canCollectCallFromInfo(callInfo)) { + collectCallAndAllParentCalls.bind(this)(call, callRecord); + } else { + // validate non-collected calls + ValidatorBuilder.build(CallValidator).checkIsViolated(call, callInfo); + } + if (!isFromChainCall) { + this._chainingCallData.reset(); + } + } +} + +function parametersBlockHasReceiver(params: readonly arkts.Expression[]): boolean { + return params.length > 0 && arkts.isETSParameterExpression(params[0]) && isThisParam(params[0]); +} + +function isThisParam(node: arkts.Expression | undefined): boolean { + if (node === undefined || !arkts.isETSParameterExpression(node)) { + return false; + } + return node.ident?.isReceiver ?? false; +} + +function parametrizedNodeHasReceiver(node: arkts.ScriptFunction | undefined): boolean { + if (node === undefined) { + return false; + } + return parametersBlockHasReceiver(node.params); +} + +function checkParentHasChainInThisCall(thisCall: arkts.CallExpression, parent: arkts.CallExpression): boolean { + const parentCallee = parent.callee; + if (parentCallee?.findNodeInInnerChild(thisCall)) { + // this impiles the parent call has inner callee of this call. + return true; + } + const args = parent.arguments; + if (args.length === 0 || !args.at(0)) { + return false; + } + const firstArg = args.at(0)!; + if (firstArg.peer === thisCall.peer || firstArg.findNodeInInnerChild(thisCall)) { + // whether the first argument has inner child of this call, impling possible function receiver call. + const callee = findRootCallee(parent.callee); + const decl = !!callee ? arkts.getPeerIdentifierDecl(callee.peer) : undefined; + return !!decl && arkts.isMethodDefinition(decl) && parametrizedNodeHasReceiver(decl.function); + } + return false; +} + +function collectCallAndAllParentCalls( + this: CallRecordCollector, + call: arkts.CallExpression, + callRecord: CallRecord +): void { + let prevCall: arkts.CallExpression = call; + let currParent: arkts.AstNode | undefined = call.parent; + while (!!currParent) { + if (arkts.isCallExpression(currParent)) { + if (!checkParentHasChainInThisCall(prevCall, currParent)) { + break; + } + this.collect(currParent, true); + prevCall = currParent; + } + currParent = currParent.parent; + } + const { call: lastCall, callRecord: lastCallRecord } = this.lastCallInfo ?? { call, callRecord }; + // validate collected calls + ValidatorBuilder.build(CallValidator).checkIsViolated(lastCall, lastCallRecord.toRecord()); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(lastCall, lastCallRecord.toJSON()); + this.chainingCallData.reset(); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/chaining-call-data-source.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/chaining-call-data-source.ts new file mode 100644 index 0000000000000000000000000000000000000000..1de140415e4f2f37f787fae51a6ad962bde5e348 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/chaining-call-data-source.ts @@ -0,0 +1,61 @@ +/* + * 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 { CallRecordInfo } from './shared-types'; +import { CallInfo } from './records'; + +export class ChainingCallDataSource { + rootCallInfo: CallRecordInfo | undefined; + chainingCallInfos: CallInfo[] = []; + chainingCalls: arkts.CallExpression[] = []; + private static instance: ChainingCallDataSource; + + private constructor() { + this.rootCallInfo = undefined; + this.chainingCallInfos = []; + this.chainingCalls = []; + } + + static getInstance(): ChainingCallDataSource { + if (!this.instance) { + this.instance = new ChainingCallDataSource(); + } + return this.instance; + } + + isWithInChain(): boolean { + return !!this.rootCallInfo && !!this.chainingCallInfos && this.chainingCallInfos.length > 0; + } + + setRootCallInfo(rootCallInfo: CallRecordInfo): this { + if (!this.rootCallInfo) { + this.rootCallInfo = rootCallInfo; + } + return this; + } + + addChainingCallInfo(call: arkts.CallExpression, chainingCallInfo: CallInfo): this { + this.chainingCallInfos.push(chainingCallInfo); + this.chainingCalls.push(call); + return this; + } + + reset(): void { + this.rootCallInfo = undefined; + this.chainingCallInfos = []; + this.chainingCalls = []; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/condition-scope-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/condition-scope-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a66e25f6fb5bee6a114d0c5a0756d882967b4c7 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/condition-scope-collector.ts @@ -0,0 +1,47 @@ +/* + * 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'; +import { checkIsCustomComponentFromInfo } from './utils'; + +export interface ConditionScopeCollectorOptions extends VisitorOptions { + +} + +export class ConditionScopeCollector extends AbstractVisitor { + constructor(options: ConditionScopeCollectorOptions) { + super(options); + } + + reset(): void { + + } + + visitor(node: arkts.ArrowFunctionExpression): arkts.ArrowFunctionExpression { + + return node; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/factory.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..9683b9a683ddd03aee86ffd89c505838026262ee --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/factory.ts @@ -0,0 +1,248 @@ +/* + * 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, + checkIsETSGlobalClassFromInfo, + checkIsCommonMethodInterfaceFromInfo, + checkCanCollectNormalClassFromInfo, + checkIsComponentAttributeInterfaceFromInfo, + checkIsDialogControllerNewInstanceFromInfo, +} from './utils'; +import { + ArrowFunctionRecord, + CustomComponentInterfaceRecord, + CustomComponentRecord, + NewClassInstanceRecord, + NormalClassRecord, + NormalInterfaceRecord, + ParameterRecord, + PropertyRecord, + RecordCache, +} 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 { NormalClassValidator, NormalInterfaceValidator, StructValidator, ValidatorBuilder } from './validators'; +import { ARKUI_IMPORT_PREFIX_NAMES, NodeCacheNames } from '../../common/predefines'; +import { matchPrefix } from '../../common/arkts-utils'; +import { getPerfName } from '../../common/debug'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export function findAndCollectUINodeInPreOrder(node: arkts.AstNode, metadata?: UICollectMetadata): void { + const type = arkts.nodeType(node); + collectUINodeByTypeInPreOrder(type, node, metadata); +} + +export function collectUINodeByTypeInPreOrder( + type: arkts.Es2pandaAstNodeType, + node: arkts.AstNode, + metadata?: UICollectMetadata +): void { + if (preOrderCollectByType.has(type)) { + const func = preOrderCollectByType.get(type)!; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([0, 1, 1], func.name)); + func(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([0, 1, 1], func.name)); + } +} + +export function findAndCollectUINodeInPostOrder(node: arkts.AstNode, metadata?: UICollectMetadata): void { + const type = arkts.nodeType(node); + collectUINodeByTypeInPostOrder(type, node, metadata); +} + +export function collectUINodeByTypeInPostOrder( + type: arkts.Es2pandaAstNodeType, + node: arkts.AstNode, + metadata?: UICollectMetadata +): void { + if (postOrderCollectByType.has(type)) { + const func = postOrderCollectByType.get(type)!; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([0, 1, 2], func.name)); + func(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([0, 1, 2], func.name)); + } +} + +export class CollectFactory { + static findAndCollectClass(node: arkts.ClassDeclaration, metadata: UICollectMetadata): arkts.AstNode { + const isFromArkUI: boolean = + !!metadata.externalSourceName && matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, metadata.externalSourceName); + const structRecord = new CustomComponentRecord(metadata); + structRecord.withIsFromArkUI(isFromArkUI).collect(node); + + let classInfo = structRecord.toRecord(); + if (!!classInfo && checkIsCustomComponentFromInfo(classInfo)) { + ValidatorBuilder.build(StructValidator).checkIsViolated(node, classInfo); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, structRecord.toJSON()); + const structCollector = new StructCollector({ ...metadata, structRecord }); + structCollector.visitor(node); + structCollector.reset(); + return node; + } + if (!!classInfo && checkIsCustomComponentDeclaredClassFromInfo(classInfo)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, structRecord.toJSON()); + const structCollector = new StructCollector({ ...metadata, structRecord }); + structCollector.disableCollectProperty().visitor(node); + structCollector.reset(); + return node; + } + + const classRecord = new NormalClassRecord(metadata); + classRecord.collect(node); + + classInfo = classRecord.toRecord(); + if (!classInfo) { + return node; + } + ValidatorBuilder.build(NormalClassValidator).checkIsViolated(node, classInfo); + if (checkCanCollectNormalClassFromInfo(classInfo)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, classRecord.toJSON()); + } + if (checkIsETSGlobalClassFromInfo(classInfo)) { + const globalClassCollector = new GlobalClassCollector(metadata); + globalClassCollector.visitor(node); + if (globalClassCollector.shouldCollectGlobalClass) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, classRecord.toJSON()); + } + globalClassCollector.reset(); + return node; + } + const normalClassCollector = new NormalClassCollector({ ...metadata, classRecord }); + normalClassCollector.visitor(node); + normalClassCollector.reset(); + 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)) { + const interfaceCollector = new StructInterfaceCollector({ ...metadata, interfaceRecord }); + interfaceCollector.visitor(node); + interfaceCollector.reset(); + return node; + } + + const normalInterfaceRecord = new NormalInterfaceRecord(metadata); + normalInterfaceRecord.collect(node); + + interfaceInfo = normalInterfaceRecord.toRecord(); + ValidatorBuilder.build(NormalInterfaceValidator).checkIsViolated(node, interfaceInfo); + if (checkIsComponentAttributeInterfaceFromInfo(interfaceInfo)) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(node, normalInterfaceRecord.toJSON()); + } else if ( + !!metadata.externalSourceName && + matchPrefix(ARKUI_IMPORT_PREFIX_NAMES, metadata.externalSourceName) && + checkIsCommonMethodInterfaceFromInfo(interfaceInfo) + ) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(node, normalInterfaceRecord.toJSON()); + } + + const interfaceCollector = new NormalInterfaceCollector({ + ...metadata, + interfaceRecord: normalInterfaceRecord, + }); + interfaceCollector.visitor(node); + interfaceCollector.reset(); + + return node; + } + + static findAndCollectCall(node: arkts.CallExpression, metadata: UICollectMetadata): arkts.AstNode { + CallRecordCollector.getInstance(metadata).withExternalSourceName(metadata.externalSourceName).collect(node); + return node; + } + + static findAndCollectParameter(node: arkts.ETSParameterExpression, metadata: UICollectMetadata): arkts.AstNode { + const parameterRecord = new ParameterRecord(metadata); + parameterRecord.collect(node); + const parameterInfo = parameterRecord.toRecord(); + if (parameterInfo?.annotationInfo?.hasBuilder) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, parameterRecord.toJSON()); + } + return node; + } + + static findAndCollectArrowFunction( + node: arkts.ArrowFunctionExpression, + metadata: UICollectMetadata + ): arkts.AstNode { + const arrowFunctionRecord = new ArrowFunctionRecord(metadata); + arrowFunctionRecord.collect(node); + const arrowFunctionInfo = arrowFunctionRecord.toRecord(); + if (arrowFunctionInfo?.annotationInfo?.hasBuilder) { + RecordCache.getInstance().set(node.peer, arrowFunctionRecord); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(node, arrowFunctionRecord.toJSON()); + } + return node; + } + + static findAndCollectProperty(node: arkts.Property, metadata: UICollectMetadata): arkts.AstNode { + const propertyRecord = new PropertyRecord(metadata); + propertyRecord.collect(node); + const propertyInfo = propertyRecord.toRecord(); + if (propertyInfo?.annotationInfo?.hasBuilder) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, propertyRecord.toJSON()); + } + return node; + } + + static findAndCollectNewClassInstance( + node: arkts.ETSNewClassInstanceExpression, + metadata: UICollectMetadata + ): arkts.AstNode { + const newClassInstanceRecord = new NewClassInstanceRecord(metadata); + newClassInstanceRecord.collect(node); + const newClassInstanceInfo = newClassInstanceRecord.toRecord(); + if (checkIsDialogControllerNewInstanceFromInfo(newClassInstanceInfo)) { + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.UI) + .collect(node, newClassInstanceRecord.toJSON()); + } + 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_ETS_NEW_CLASS_INSTANCE_EXPRESSION, + CollectFactory.findAndCollectNewClassInstance, + ], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION, CollectFactory.findAndCollectParameter], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION, CollectFactory.findAndCollectArrowFunction], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_PROPERTY, CollectFactory.findAndCollectProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, CollectFactory.findAndCollectCall], +]); diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/global-class-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/global-class-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..9af8522951b4b3fb36b8a504136a4c560a68488b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/global-class-collector.ts @@ -0,0 +1,98 @@ +/* + * 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 { ARKUI_BUILDER_SOURCE_NAME, NodeCacheNames } from '../../common/predefines'; +import { FunctionInfo, FunctionRecord } from './records/function'; +import { FunctionValidator, GlobalPropertyValidator, ValidatorBuilder } from './validators'; +import { GLobalPropertyRecord } from './records'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export interface GlobalClassCollectorOptions extends VisitorOptions { + shouldIgnoreDecl?: boolean; +} + +export class GlobalClassCollector extends AbstractVisitor { + public shouldIgnoreDecl: boolean; + public shouldCollectGlobalClass?: boolean; + + constructor(options: GlobalClassCollectorOptions) { + super(options); + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + } + + private canCollectMethodFromInfo(info: FunctionInfo): boolean { + if (!!info.annotationInfo && Object.keys(info.annotationInfo).length > 0) { + return true; + } + if (!!info.innerComponentInfo?.attributeName) { + return true; + } + return false; + } + + private canCollectGlobalClassFromMethodInfo(info: FunctionInfo): boolean { + if (!!info.innerComponentInfo?.attributeName) { + return true; + } + return 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; + } + ValidatorBuilder.build(FunctionValidator).checkIsViolated(node, methodInfo); + if (this.canCollectMethodFromInfo(methodInfo)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + } + this.shouldCollectGlobalClass ||= this.canCollectGlobalClassFromMethodInfo(methodInfo); + } + + private collectProperty(node: arkts.ClassProperty): void { + const propertyRecord = new GLobalPropertyRecord({ + shouldIgnoreDecl: this.shouldIgnoreDecl, + }); + propertyRecord.collect(node); + + const propertyInfo = propertyRecord.toRecord(); + if (!propertyInfo) { + return; + } + ValidatorBuilder.build(GlobalPropertyValidator).checkIsViolated(node, propertyInfo); + } + + visitor(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + node.definition?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + st.overloads.forEach((method) => this.collectMethod(method)); + } else if (arkts.isClassProperty(st)) { + this.collectProperty(st); + } + }); + if (!!this.externalSourceName && this.externalSourceName === ARKUI_BUILDER_SOURCE_NAME) { + this.shouldCollectGlobalClass ||= true; + } + return node; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/normal-class-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/normal-class-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab0632c95429b46c7a9a2befaa842ef1b9892b85 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/normal-class-collector.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 { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; +import { + NormalClassMethodInfo, + NormalClassMethodRecord, + NormalClassPropertyInfo, + NormalClassPropertyRecord, + NormalClassRecord, +} from './records'; +import { BaseRecord } from './records/base'; +import { BuiltInNames, EntryWrapperNames, NodeCacheNames } from '../../common/predefines'; +import { formatBuiltInInheritPropertyName, getArkUIAnnotationNames } from './utils'; +import { NormalClassMethodValidator, NormalClassPropertyValidator, ValidatorBuilder } from './validators'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export interface NormalClassCollectorOptions extends VisitorOptions { + classRecord: NormalClassRecord; + shouldIgnoreDecl?: boolean; +} + +type RecordCollection, U extends BaseRecord> = { + node: T; + info: S; + record: U; +}; + +type MethodRecordCollection = RecordCollection; + +type PropertyRecordCollection = RecordCollection< + arkts.ClassProperty, + NormalClassPropertyInfo, + NormalClassPropertyRecord +>; + +export class NormalClassCollector extends AbstractVisitor { + private _classRecord: NormalClassRecord; + public shouldIgnoreDecl: boolean; + + private _rememberedMethods: MethodRecordCollection[]; + private _rememberedProperties: PropertyRecordCollection[]; + + constructor(options: NormalClassCollectorOptions) { + super(options); + this._classRecord = options.classRecord; + this.shouldIgnoreDecl = options.shouldIgnoreDecl ?? false; + this._rememberedMethods = []; + this._rememberedProperties = []; + } + + private canRememberPropertyFromInfo(info: NormalClassPropertyInfo): boolean { + if (info.classInfo?.annotationInfo?.hasObserved) { + return true; + } + if (info.classInfo?.annotationInfo?.hasObservedV2) { + return true; + } + return false; + } + + private canCollectPropertyFromInfo(info: NormalClassPropertyInfo): boolean { + if (getArkUIAnnotationNames(info.annotations, info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private canRememberMethodFromInfo(info: NormalClassMethodInfo): boolean { + const kind: arkts.Es2pandaMethodDefinitionKind | undefined = info.kind; + if (!kind) { + return false; + } + return ( + kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET || + kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET + ); + } + + private canCollectMethodFromInfo(info: NormalClassMethodInfo): boolean { + if (info.classInfo?.name === EntryWrapperNames.WRAPPER_CLASS_NAME) { + return true; + } + if (getArkUIAnnotationNames(info.annotations, info.annotationInfo).length > 0) { + return true; + } + return false; + } + + private findTrackPropertyInObservedClass(info: NormalClassPropertyInfo): boolean { + return !!info.classInfo?.annotationInfo?.hasObserved && !!info.annotationInfo?.hasTrack; + } + + private collectClassFromTrackProperty(classDecl: arkts.ClassDeclaration, info: NormalClassPropertyInfo): void { + if (!info.annotationInfo?.hasTrack) { + return; + } + this._classRecord.setHasTrackProperty(true); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(classDecl, this._classRecord.toJSON()); + } + + private collectProperty( + node: arkts.ClassProperty, + withInfoCallback?: (node: arkts.ClassProperty, info: NormalClassPropertyInfo) => void + ): 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)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, propertyRecord.toJSON()); + } + if (this.canRememberPropertyFromInfo(propertyInfo)) { + this._rememberedProperties.push({ info: propertyInfo, node, record: propertyRecord }); + } + withInfoCallback?.(node, propertyInfo); + ValidatorBuilder.build(NormalClassPropertyValidator).checkIsViolated(node, propertyInfo); + } + + private canSkipCollectRememberProperty(info: NormalClassPropertyInfo, hasTrackInObservedClass: boolean): boolean { + const hasObservedV2 = info.classInfo?.annotationInfo?.hasObservedV2; + if (!!hasObservedV2) { + return !info.annotationInfo?.hasTrace; + } + const hasTrack = info.annotationInfo?.hasTrack; + const hasObserved = info.classInfo?.annotationInfo?.hasObserved; + return !hasTrack && (!!hasTrackInObservedClass || !hasObserved); + } + + private collectRememberedProperty( + collection: PropertyRecordCollection, + shouldSkip: (collection: PropertyRecordCollection) => boolean, + withCollectCallback?: (collection: PropertyRecordCollection) => void + ): void { + if (shouldSkip(collection)) { + return; + } + const { node, record } = collection; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, record.toJSON()); + withCollectCallback?.(collection); + } + + private setInheritPropertyRecord( + collection: PropertyRecordCollection, + inheritPropertyRecords: Map + ): Map { + const { info, record } = collection; + const name = info.name!; + if (name.startsWith(BuiltInNames.IMPLEMENT_PROPETY_PREFIX)) { + const propertyName: string = formatBuiltInInheritPropertyName(name); + inheritPropertyRecords.set(propertyName, record); + } + return inheritPropertyRecords; + } + + 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.canCollectMethodFromInfo(methodInfo)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + } else if (this.canRememberMethodFromInfo(methodInfo)) { + this._rememberedMethods.push({ info: methodInfo, node, record: methodRecord }); + } + ValidatorBuilder.build(NormalClassMethodValidator).checkIsViolated(node, methodInfo); + } + + private collectRememberedMethod( + collection: MethodRecordCollection, + inheritPropertyRecords?: Map + ): void { + const { info, node, record } = collection; + const name = info.name!; + if (!inheritPropertyRecords?.has(name)) { + return; + } + const propertyRecord = inheritPropertyRecords.get(name)!; + const methodInfo = record.withInheritPropertyRecord(propertyRecord).toJSON(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodInfo); + } + + reset(): void { + super.reset(); + this._rememberedMethods = []; + this._rememberedProperties = []; + } + + visitor(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + let _hasTrackInObservedClass: boolean = false; + let _inheritPropertyRecords: Map = new Map(); + node.definition?.body.forEach((st) => { + if (arkts.isClassProperty(st)) { + this.collectProperty(st, (_node, info) => { + this.collectClassFromTrackProperty(node, info); + _hasTrackInObservedClass ||= this.findTrackPropertyInObservedClass(info); + }); + } else if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + st.overloads.forEach((o) => this.collectMethod(o)); + } + }); + this._rememberedProperties.forEach((collection) => { + this.collectRememberedProperty( + collection, + (c) => { + const { info } = c; + return this.canSkipCollectRememberProperty(info, _hasTrackInObservedClass); + }, + (c) => { + _inheritPropertyRecords = this.setInheritPropertyRecord(c, _inheritPropertyRecords); + } + ); + }); + this._rememberedMethods.forEach((collection) => { + this.collectRememberedMethod(collection, _inheritPropertyRecords); + }); + return node; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/normal-interface-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..5391af0232f88911bb017d796222d8177dba68a5 --- /dev/null +++ b/ui2abc/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 { CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, NodeCacheNames } from '../../common/predefines'; +import { MetaDataCollector } from '../../common/metadata-collector'; +import { checkIsCustomDialogControllerBuilderOptionsFromInfo } from './utils'; +import { NodeCacheFactory } from '../../common/node-cache'; + +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; + } + if (MetaDataCollector.getInstance().externalSourceName === CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME) { + return checkIsCustomDialogControllerBuilderOptionsFromInfo(info); + } + 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)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + } + } + + visitor(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + node.body?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/arrow-function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/arrow-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae990205f2eadf05f1899f385822209149b471e6 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/arrow-function.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 { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { BuilderLambdaNames, DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface ArrowFunctionAnnotationInfo extends AnnotationInfo { + hasBuilder?: boolean; +} + +export interface ArrowFunctionAnnotations extends Annotations { + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; +} + +export class ArrowFunctionAnnotationRecord extends BaseAnnotationRecord< + ArrowFunctionAnnotations, + ArrowFunctionAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.annotationNames = [DecoratorNames.BUILDER]; + } + + updateAnnotationInfoByName( + info: ArrowFunctionAnnotationInfo, + name: string | undefined + ): ArrowFunctionAnnotationInfo { + switch (name) { + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts new file mode 100644 index 0000000000000000000000000000000000000000..226767a1fd1d1e38b9d376149678ee764c288395 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/base.ts @@ -0,0 +1,141 @@ +/* + * 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 = {}; + + private _allAnnotationsAsIgnored: boolean = false; + + constructor(options: RecordOptions) { + super(options); + } + + withAllAnnotationsAsIgnored(): this { + this._allAnnotationsAsIgnored = true; + return this; + } + + 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); + if (!this._allAnnotationsAsIgnored) { + 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/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..64549d6efc2ab5c9df0ef3e2f6fab60a19a6ab4d --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/call-declaration.ts @@ -0,0 +1,80 @@ +/* + * 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.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.OBJECT_LINK, + DecoratorNames.WATCH, + DecoratorNames.BUILDER_PARAM, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.PROP_REF, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL_STORAGE_PROP_REF, + DecoratorNames.LOCAL, + DecoratorNames.ONCE, + DecoratorNames.PARAM, + DecoratorNames.EVENT, + DecoratorNames.REQUIRE, + DecoratorNames.CONSUMER, + DecoratorNames.PROVIDER, + DecoratorNames.COMPUTED, + DecoratorNames.MONITOR, + DecoratorNames.JSONSTRINGIFYIGNORE, + DecoratorNames.JSONRENAME, + DecoratorNames.TRACK, + DecoratorNames.TRACE, + ]; + } + + updateAnnotationInfoByName(info: CallDeclAnnotationInfo, name: string | undefined): CallDeclAnnotationInfo { + if (!!name && this.annotationNames.includes(name)) { + info[`has${name}`] = true; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a8c56d3d23e357ead7dc853174505464a040d0b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/custom-component.ts @@ -0,0 +1,85 @@ +/* + * 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; + hasPreview?: 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; + [StructDecoratorNames.PREVIEW]?: arkts.AnnotationUsage; +} + +export class CustomComponentAnnotationRecord extends BaseAnnotationRecord< + CustomComponentAnnotations, + StructAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + 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; + case StructDecoratorNames.PREVIEW: + info.hasPreview = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5ae1d75edb47c3dc4d61bc5b7b687f42ed51eca --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/function.ts @@ -0,0 +1,61 @@ +/* + * 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.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..566e1439eb9e06bea6886893fc70791048f6ea0d --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/index.ts @@ -0,0 +1,26 @@ +/* + * 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'; +export * from './parameter'; +export * from './arrow-function'; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..66102104a0fa91738d95d261089deb6faeec69bc --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-method.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 { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface NormalClassMethodAnnotationInfo extends AnnotationInfo { + hasComputed?: boolean; + hasMonitor?: boolean; +} + +export interface NormalClassMethodAnnotations extends Annotations { + [DecoratorNames.COMPUTED]?: arkts.AnnotationUsage; + [DecoratorNames.MONITOR]?: arkts.AnnotationUsage; +} + +export class NormalClassMethodAnnotationRecord extends BaseAnnotationRecord< + NormalClassMethodAnnotations, + NormalClassMethodAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.annotationNames = [DecoratorNames.COMPUTED, DecoratorNames.MONITOR]; + } + + updateAnnotationInfoByName( + info: NormalClassMethodAnnotationInfo, + name: string | undefined + ): NormalClassMethodAnnotationInfo { + switch (name) { + case DecoratorNames.COMPUTED: + info.hasComputed = true; + break; + case DecoratorNames.MONITOR: + info.hasMonitor = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..23ffa491a0b61df35e329bc81b7b3ca9a3e90b47 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class-property.ts @@ -0,0 +1,68 @@ +/* + * 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; + hasTrace?: boolean; +} + +export interface NormalClassPropertyAnnotations extends Annotations { + [DecoratorNames.JSONSTRINGIFYIGNORE]?: arkts.AnnotationUsage; + [DecoratorNames.JSONRENAME]?: arkts.AnnotationUsage; + [DecoratorNames.TRACK]?: arkts.AnnotationUsage; + [DecoratorNames.TRACE]?: arkts.AnnotationUsage; +} + +export class NormalClassPropertyAnnotationRecord extends BaseAnnotationRecord< + NormalClassPropertyAnnotations, + NormalClassPropertyAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + 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; + case DecoratorNames.TRACE: + info.hasTrace = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..f087f8393736ba72285c662fe60143efee928638 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-class.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 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.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..2809075bd955780430d8b9dba4d2cd3b089e4c00 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/normal-interface-property.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 { 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.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/parameter.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..54b472fd91d2d7d296e4367bf62586f393f4fb77 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/parameter.ts @@ -0,0 +1,48 @@ +/* + * 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 ParameterAnnotationInfo extends AnnotationInfo { + hasBuilder?: boolean; +} + +export interface ParameterAnnotations extends Annotations { + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; +} + +export class ParameterAnnotationRecord extends BaseAnnotationRecord { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.shouldIgnoreDecl = false; + this.annotationNames = [DecoratorNames.BUILDER]; + } + + updateAnnotationInfoByName(info: ParameterAnnotationInfo, name: string | undefined): ParameterAnnotationInfo { + switch (name) { + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d94e51c0cabc66b2479b926e17b70d88f32d1fb --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-method.ts @@ -0,0 +1,70 @@ +/* + * 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 StructMethodAnnotationInfo extends AnnotationInfo { + hasComponentBuilder?: boolean; + hasBuilder?: boolean; + hasComputed?: boolean; + hasMonitor?: boolean; +} + +export interface StructMethodAnnotations extends Annotations { + [BuilderLambdaNames.ANNOTATION_NAME]?: arkts.AnnotationUsage; + [DecoratorNames.BUILDER]?: arkts.AnnotationUsage; + [DecoratorNames.COMPUTED]?: arkts.AnnotationUsage; + [DecoratorNames.MONITOR]?: arkts.AnnotationUsage; +} + +export class StructMethodAnnotationRecord extends BaseAnnotationRecord< + StructMethodAnnotations, + StructMethodAnnotationInfo +> { + protected annotationNames: string[]; + + constructor(options: RecordOptions) { + super(options); + this.annotationNames = [ + BuilderLambdaNames.ANNOTATION_NAME, + DecoratorNames.BUILDER, + DecoratorNames.COMPUTED, + DecoratorNames.MONITOR, + ]; + } + + updateAnnotationInfoByName(info: StructMethodAnnotationInfo, name: string | undefined): StructMethodAnnotationInfo { + switch (name) { + case BuilderLambdaNames.ANNOTATION_NAME: + info.hasComponentBuilder = true; + break; + case DecoratorNames.BUILDER: + info.hasBuilder = true; + break; + case DecoratorNames.COMPUTED: + info.hasComputed = true; + break; + case DecoratorNames.MONITOR: + info.hasMonitor = true; + break; + default: + return info; + } + return info; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..fec90ce3c58728835762fd10127778977cc3d09f --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/annotations/struct-property.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 { AnnotationInfo, Annotations, BaseAnnotationRecord } from './base'; +import { DecoratorNames } from '../../../../common/predefines'; +import { RecordOptions } from '../base'; + +export interface StructPropertyAnnotationInfo extends AnnotationInfo { + hasState?: boolean; + hasStorageLink?: boolean; + hasLink?: boolean; + hasProvide?: boolean; + hasConsume?: boolean; + hasObjectLink?: boolean; + hasWatch?: boolean; + hasBuilderParam?: boolean; + hasLocalStorageLink?: boolean; + hasPropRef?: boolean; + hasStoragePropRef?: boolean; + hasLocalStoragePropRef?: boolean; + hasLocal?: boolean; + hasOnce?: 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.LINK]?: 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_LINK]?: arkts.AnnotationUsage; + [DecoratorNames.PROP_REF]?: arkts.AnnotationUsage; + [DecoratorNames.STORAGE_PROP_REF]?: arkts.AnnotationUsage; + [DecoratorNames.LOCAL_STORAGE_PROP_REF]?: arkts.AnnotationUsage; + [DecoratorNames.LOCAL]?: arkts.AnnotationUsage; + [DecoratorNames.ONCE]?: 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 = false; + this.annotationNames = [ + DecoratorNames.STATE, + DecoratorNames.STORAGE_LINK, + DecoratorNames.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.OBJECT_LINK, + DecoratorNames.WATCH, + DecoratorNames.BUILDER_PARAM, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.PROP_REF, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL_STORAGE_PROP_REF, + DecoratorNames.LOCAL, + DecoratorNames.ONCE, + 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/ui2abc/arkui-plugins/collectors/ui-collectors/records/arrow-function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/arrow-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..848b693fc4535459a9a9442d42dce16cf4f301be --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/arrow-function.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 { ArrowFunctionAnnotationInfo, ArrowFunctionAnnotationRecord, ArrowFunctionAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; + +export type ArrowFunctionInfo = AnnotationRecord & {}; + +export class ArrowFunctionRecord extends BaseRecord { + private _annotationRecord?: ArrowFunctionAnnotationRecord; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new ArrowFunctionAnnotationRecord(options); + } + + collectFromNode(node: arkts.ArrowFunctionExpression): void { + for (const anno of node.annotations) { + this._annotationRecord?.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): ArrowFunctionInfo { + this.refresh(); + return { + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/base.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/base.ts new file mode 100644 index 0000000000000000000000000000000000000000..8060a51b93fc4fbbb45dedb74b30fdf7870fa405 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/base.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'; + +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; + } + + get shouldIgnoreDecl(): boolean { + return this._shouldIgnoreDecl; + } + + set shouldIgnoreDecl(value: boolean) { + this._shouldIgnoreDecl = value; + } + + 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; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/cache.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/cache.ts new file mode 100644 index 0000000000000000000000000000000000000000..cff03321b5cf06183b0bf3b0ae671e845b0babeb --- /dev/null +++ b/ui2abc/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(): AstNodePointer[] { + 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(): [AstNodePointer, 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/ui2abc/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5dcae118c23420326d4bffa99a5413c8d86decb --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/call-declaration.ts @@ -0,0 +1,169 @@ +/* + * 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, LANGUAGE_VERSION } from '../../../common/predefines'; +import { FileManager } from '../../../common/file-manager'; + +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; + + /** + * whether declaration node is from legacy application. + */ + isDeclFromLegacy?: 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; + protected isDeclFromLegacy?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new CallDeclAnnotationRecord(options); + } + + private collectAnnotations(annotations: readonly arkts.AnnotationUsage[], isFromLegacy?: boolean): void { + if (!!isFromLegacy) { + this._annotationRecord.shouldIgnoreDecl = true; + } + 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, isFromLegacy?: boolean): void { + this.collectAnnotations(node.function.annotations, isFromLegacy); + this.declName = node.id?.name; + this.modifiers = node.modifiers; + this.hasReceiver = node.function.hasReceiver; + if ( + !!node.parent && + arkts.isMethodDefinition(node.parent) && + node.parent.id?.name === BuiltInNames.ETS_GLOBAL_CLASS + ) { + this.isDeclFromFunction = true; + } else { + this.isDeclFromMethod = true; + } + } + + private collectFromLegacy(sourceProgram: arkts.Program | undefined): void { + const path = sourceProgram?.absoluteName; + if (!path) { + return; + } + const fileManager = FileManager.getInstance(); + this.isDeclFromLegacy = fileManager.getLanguageVersionByFilePath(path) === LANGUAGE_VERSION.ARKTS_1_1; + } + + protected collectFromNode(node: arkts.AstNode): void { + const sourceProgram = arkts.getProgramFromAstNode(node); + this.moduleName = sourceProgram?.moduleName; + if (arkts.isClassProperty(node)) { + this.collectFromClassProperty(node); + } else if (arkts.isMethodDefinition(node)) { + this.collectFromLegacy(sourceProgram); + this.collectFromMethod(node, this.isDeclFromLegacy); + } + } + + protected refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + currInfo = { + ...currInfo, + ...(this.declName && { declName: this.declName }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(this.hasReceiver && { hasReceiver: this.hasReceiver }), + ...(this.moduleName && { moduleName: this.moduleName }), + ...(this.isDeclFromClassProperty && { isDeclFromClassProperty: this.isDeclFromClassProperty }), + ...(this.isDeclFromMethod && { isDeclFromMethod: this.isDeclFromMethod }), + ...(this.isDeclFromFunction && { isDeclFromFunction: this.isDeclFromFunction }), + ...(this.isDeclFromLegacy && { isDeclFromLegacy: this.isDeclFromLegacy }), + ...(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?.hasReceiver && { hasReceiver: this.info.hasReceiver }), + ...(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?.isDeclFromLegacy && { isDeclFromLegacy: this.info.isDeclFromLegacy }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/function-call.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/function-call.ts new file mode 100644 index 0000000000000000000000000000000000000000..a04190807e90fc03d7daef8d1fa8c26e1c22f07b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/function-call.ts @@ -0,0 +1,422 @@ +/* + * 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, + checkIsStructFromNode, + findRootCallee, + findRootCallObject, + 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'; +import { + CustomComponentInterfacePropertyInfo, + CustomComponentInterfacePropertyRecord, +} from './struct-interface-property'; + +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 infos start from the root call to this call in a chain (root call exclusive) + */ + chainingCallInfos?: CallInfo[]; + + /** + * 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 this 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 call's options argument information, call is not a struct call or no options argument if not exist + */ + structPropertyInfos?: [AstNodePointer, CustomComponentInterfacePropertyInfo | undefined][]; + + /** + * 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; + private _structPropertyRecords?: [AstNodePointer, CustomComponentInterfacePropertyRecord][]; + + 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 _chainingCallInfos?: CallInfo[]; + + constructor(options: RecordOptions) { + super(options); + this._declRecord = new CallDeclRecord(options); + } + + get callPtr(): AstNodePointer | undefined { + return this.ptr; + } + + 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 chainingCallInfos(): CallInfo[] | undefined { + return this._chainingCallInfos; + } + + protected set chainingCallInfos(chainingCallInfos: CallInfo[] | undefined) { + this._chainingCallInfos = chainingCallInfos; + this.isChanged = true; + } + + protected get isStructCall(): boolean { + return !!this._structDeclRecord?.isCollected || !!this.rootCallInfo?.structDeclInfo || !!this.structDeclInfo; + } + + 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 { + const struct = structNode?.parent; + if (!struct || !arkts.isClassDeclaration(struct) || !checkIsStructFromNode(struct)) { + return; + } + const _record = RecordBuilder.build(CustomComponentRecord, struct, this.getOptions()); + this._structDeclRecord = _record; + if (!this._structDeclRecord.isCollected) { + this._structDeclRecord.collect(struct); + } + } + + private collectStructPropertyInfoFromStructCall(call: arkts.CallExpression): void { + if (!this.isStructCall || !!this._structPropertyRecords) { + return; + } + const optionsArg = call.arguments.at(1); // Options is the second argument of a custom component call. + if (!optionsArg || !arkts.isObjectExpression(optionsArg)) { + return; + } + const records: [AstNodePointer, CustomComponentInterfacePropertyRecord][] = []; + (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; + } + const structInterfacePropRecord = RecordBuilder.build( + CustomComponentInterfacePropertyRecord, + decl, + this.getOptions() + ); + if (!structInterfacePropRecord.isCollected) { + structInterfacePropRecord.collect(decl); + } + records.push([prop.peer, structInterfacePropRecord]); + }); + if (Object.keys(records).length > 0) { + this._structPropertyRecords = records; + } + } + + private collectFromStructInfo(structNode: arkts.ClassDefinition | undefined): void { + const struct = structNode?.parent; + if (!struct || !arkts.isClassDeclaration(struct) || !checkIsStructFromNode(struct)) { + return; + } + const _record = RecordBuilder.build(CustomComponentRecord, struct, this.getOptions()); + this._fromStructRecord = _record; + if (!this._fromStructRecord.isCollected) { + this._fromStructRecord.collect(struct); + } + } + + 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; + } + + withChainingCallInfos(chainingCallInfos: CallInfo[]): this { + this.chainingCallInfos = chainingCallInfos; + return this; + } + + collectFromNode(node: arkts.CallExpression): void { + this.ptr = node.peer; + + const callee = node.callee; + 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(); + this.collectStructPropertyInfoFromStructCall(node); + + if (!!this._rootCallee) { + const decl = arkts.getPeerIdentifierDecl(this._rootCallee.peer); + this.collectFromDecl(decl); + this.findIsSpecialCall(decl); + } + } + + toPropertyRecords(): [AstNodePointer, CustomComponentInterfacePropertyInfo | undefined][] | undefined { + if (!this._structPropertyRecords) { + return undefined; + } + const records: [AstNodePointer, CustomComponentInterfacePropertyInfo | undefined][] = []; + this._structPropertyRecords.forEach((record) => { + records.push([record[0], record[1].toRecord()]); + }); + return records; + } + + 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(); + const structPropertyInfos = this.toPropertyRecords(); + currInfo = { + ...currInfo, + ...(this.ptr && { ptr: this.ptr }), + ...(this.callName && { callName: this.callName }), + ...(this.chainingCallInfos && { chainingCallInfos: this.chainingCallInfos }), + ...(this.isThis && { isThis: this.isThis }), + ...(this.isTrailingCall && { isTrailingCall: this.isTrailingCall }), + ...(this.isBindableCall && { isBindableCall: this.isBindableCall }), + ...(this.isResourceCall && { isResourceCall: this.isResourceCall }), + ...(declRecord && { ...declRecord }), + ...(this.rootCallInfo && { rootCallInfo: this.rootCallInfo }), + ...(structDeclInfo && { structDeclInfo }), + ...(fromStructInfo && { fromStructInfo }), + ...(structPropertyInfos && { structPropertyInfos }), + }; + this.info = currInfo; + } + + toPropertyJSONs(): [AstNodePointer, CustomComponentInterfacePropertyInfo | undefined][] | undefined { + if (!this._structPropertyRecords) { + return undefined; + } + const records: [AstNodePointer, CustomComponentInterfacePropertyInfo | undefined][] = []; + this._structPropertyRecords.forEach((record) => { + records.push([-1, record[1].toJSON()]); + }); + return records; + } + + toRootCallJSON(): CallInfo | undefined { + if (!this.info || !this.info.rootCallInfo) { + return undefined; + } + const rootInfo = this.info.rootCallInfo; + return { + ...(rootInfo.callName && { callName: rootInfo.callName }), + ...(rootInfo.isThis && { isThis: rootInfo.isThis }), + ...(rootInfo.isTrailingCall && { isTrailingCall: rootInfo.isTrailingCall }), + ...(rootInfo.isBindableCall && { isBindableCall: rootInfo.isBindableCall }), + ...(rootInfo.isResourceCall && { isResourceCall: rootInfo.isResourceCall }), + ...(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 }), + }; + } + + toChainJSON(): CallInfo { + this.refresh(); + const declInfo = this._declRecord.toJSON(); + return { + ...(this.info?.callName && { callName: this.info.callName }), + ...(this.info?.isTrailingCall && { isTrailingCall: this.info.isTrailingCall }), + ...(declInfo && { ...declInfo }), + }; + } + + toJSON(): CallInfo { + this.refresh(); + const declInfo = this._declRecord.toJSON(); + const rootCallInfo = this.toRootCallJSON(); + const structDeclInfo = this._structDeclRecord?.toJSON(); + const fromStructInfo = this._fromStructRecord?.toJSON(); + const structPropertyInfos = this.toPropertyJSONs(); + return { + ...(this.info?.callName && { callName: this.info.callName }), + ...(this.info?.chainingCallInfos && { chainingCallInfos: this.info.chainingCallInfos }), + ...(this.info?.isThis && { isThis: this.info.isThis }), + ...(this.info?.isTrailingCall && { isTrailingCall: this.info.isTrailingCall }), + ...(this.info?.isBindableCall && { isBindableCall: this.info.isBindableCall }), + ...(this.info?.isResourceCall && { isResourceCall: this.info.isResourceCall }), + ...(declInfo && { ...declInfo }), + ...(rootCallInfo && { rootCallInfo }), + ...(structDeclInfo && { structDeclInfo }), + ...(fromStructInfo && { fromStructInfo }), + ...(structPropertyInfos && { structPropertyInfos }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/function.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb7aebf81a735ebd24a59e8cdc9b0b6c7ace1287 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/function.ts @@ -0,0 +1,94 @@ +/* + * 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'; +import { InnerComponentFunctionInfo, InnerComponentFunctionRecord } from './inner-component-function'; + +export type FunctionInfo = AnnotationRecord & { + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; + kind?: arkts.Es2pandaMethodDefinitionKind; + isDecl?: boolean; + isGlobalInit?: boolean; + isGlobalMain?: boolean; + innerComponentInfo?: InnerComponentFunctionInfo; +}; + +export class FunctionRecord extends BaseRecord { + private _annotationRecord?: FunctionAnnotationRecord; + private _innerComponentRecord?: InnerComponentFunctionRecord; + + 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); + this._innerComponentRecord = new InnerComponentFunctionRecord(options); + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.id?.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.function.annotations) { + this._annotationRecord?.collect(anno); + } + if (!!this._annotationRecord?.annotationInfo?.hasComponentBuilder) { + this._innerComponentRecord?.collect(node); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord?.toRecord(); + const innerComponentInfo = this._innerComponentRecord?.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 }), + ...(innerComponentInfo && { innerComponentInfo }), + }; + 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 }), + ...(this.info?.innerComponentInfo && { innerComponentInfo: this.info.innerComponentInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/global-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/global-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a3ed792336f18a38c0dd66739f8df3bd46c96e9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/global-property.ts @@ -0,0 +1,74 @@ +/* + * 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 { NormalClassPropertyAnnotationRecord } from './annotations'; +import { AnnotationInfo, AnnotationRecord, Annotations } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; + +/** + * assume `annotations` and `annotationInfo` are always `undefined`. + */ +type IgnoredAnnotationRecord = AnnotationRecord; + +export type GLobalPropertyInfo = IgnoredAnnotationRecord & { + name?: string; + modifiers?: arkts.Es2pandaModifierFlags; +}; + +export class GLobalPropertyRecord extends BaseRecord { + private _annotationRecord: NormalClassPropertyAnnotationRecord; + + protected name?: string; + protected modifiers?: arkts.Es2pandaModifierFlags; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new NormalClassPropertyAnnotationRecord(options).withAllAnnotationsAsIgnored(); + } + + 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(); + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.modifiers && { modifiers: this.modifiers }), + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): GLobalPropertyInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.modifiers && { modifiers: this.info.modifiers }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/index.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c3b0947cdcc6943badba9b5d76f85c1b1574bb9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/index.ts @@ -0,0 +1,39 @@ +/* + * 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 './global-property'; +export * from './function'; +export * from './function-call'; +export * from './record-builder'; +export * from './inner-component-function'; +export * from './parameter'; +export * from './property'; +export * from './arrow-function'; +export * from './new-class-instance'; +export * from './cache'; + +export * from './shared-types'; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/inner-component-function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/inner-component-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..b07f6231bd32a1ef3f4e230ffac9d75ad808de6f --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/inner-component-function.ts @@ -0,0 +1,259 @@ +/* + * 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 { expectNameInTypeReference } from '../../../common/arkts-utils'; +import { + collectTypeRecordFromParameter, + collectTypeRecordFromTypeParameterDeclaration, + collectTypeRecordFromTypeParameterInstantiation, + ParameterRecord, + TypeParameterTypeRecord, + TypeRecord, +} from '../../utils/collect-types'; +import { MetaDataCollector } from '../../../common/metadata-collector'; +import { ARKUI_FOREACH_SOURCE_NAME, DecoratorNames, InnerComponentNames } from '../../../common/predefines'; +import { BaseRecord, RecordOptions } from './base'; +import { AstNodePointer } from '../../../common/safe-types'; +import { isDeclFromArkUI } from '../utils'; +import { hasMemoAnnotation, MemoAstNode } from '../../memo-collectors/utils'; + +export type InnerComponentFunctionInfo = ComponentAttributeInfo & + ComponentInfo & { + hasLastTrailingLambda?: boolean; + }; + +export type ComponentInfo = { + paramRecords?: ParameterRecord[]; + typeParameters?: TypeParameterTypeRecord[]; + hasRestParameter?: boolean; + hasReceiver?: boolean; +}; + +export type ComponentAttributeInfo = { + attributeName?: string; + attributeTypeParams?: TypeRecord[]; +}; + +/** + * find attribute info from component method + */ +export function findAttributeInfoFromComponentMethod( + component: arkts.MethodDefinition +): ComponentAttributeInfo | undefined { + const type = component.function.returnTypeAnnotation; + const name = expectNameInTypeReference(type); + if (!name) { + return undefined; + } + return { + attributeName: name.name, + attributeTypeParams: collectTypeRecordFromTypeParameterInstantiation( + (name.parent as arkts.ETSTypeReferencePart).typeParams + ), + }; +} + +export function findBuilderName( + node: arkts.TypeNode | arkts.ETSParameterExpression, + ignoreDecl: boolean = false +): boolean { + const builderAnnoExpr = node.annotations.find((anno) => { + const expr = anno.expr; + if (!expr || !arkts.isIdentifier(expr)) { + return true; + } + const name = expr.name; + if (name === DecoratorNames.BUILDER) { + const decl = arkts.getPeerIdentifierDecl(expr!.peer); + if (!decl) { + return false; + } + if (!ignoreDecl && !isDeclFromArkUI(decl)) { + return false; + } + return true; + } + return name === 'memo' || name === 'Memo'; + }); + return !!builderAnnoExpr; +} + +export function checkIsTrailingLambdaType( + typeNode: arkts.AstNode | undefined, + ignoreDecl: boolean = false, + shouldIgnoreAnnotation: boolean = false +): boolean { + if (!typeNode) { + return false; + } + const queue: arkts.AstNode[] = [typeNode]; + const visitedNames: AstNodePointer[] = []; + let hasTrailingLambdaType: boolean = false; + let hasBuilderAnnotation: boolean = shouldIgnoreAnnotation; + let otherTypeLength: number = 0; + while (queue.length > 0 && otherTypeLength === 0 && !(hasTrailingLambdaType && hasBuilderAnnotation)) { + const node = queue.shift()!; + if (arkts.isETSFunctionType(node)) { + hasTrailingLambdaType ||= + node.params.length === 0 && !!node.returnType && node.returnType.dumpSrc() === 'void'; + hasBuilderAnnotation ||= findBuilderName(node, ignoreDecl); + if (!hasTrailingLambdaType && !hasBuilderAnnotation) { + otherTypeLength++; + } + } else if (arkts.isETSUnionType(node)) { + queue.push(...node.types); + hasBuilderAnnotation ||= findBuilderName(node, ignoreDecl); + } else if (arkts.isETSTypeReference(node)) { + const name = expectNameInTypeReference(node); + if (!name) { + continue; + } + const decl = !!name ? arkts.getPeerIdentifierDecl(name.peer) : undefined; + if (!decl || !arkts.isTSTypeAliasDeclaration(decl) || visitedNames.includes(decl.peer)) { + continue; + } + visitedNames.push(decl.peer); + const type = decl.typeAnnotation; + if (!type) { + continue; + } + queue.push(type); + hasBuilderAnnotation ||= findBuilderName(node, ignoreDecl); + } else if (!arkts.isETSUndefinedType(node)) { + otherTypeLength++; + } + } + return hasTrailingLambdaType && hasBuilderAnnotation && otherTypeLength === 0; +} + +/** + * check whether the last parameter is trailing lambda in components. + */ +export function checkIsTrailingLambdaInLastParam( + params: readonly arkts.Expression[], + ignoreDecl: boolean = false +): boolean { + if (params.length === 0) { + return false; + } + const lastParam = params.at(params.length - 1)! as arkts.ETSParameterExpression; + const hasBuilder = findBuilderName(lastParam, ignoreDecl); + return checkIsTrailingLambdaType(lastParam.typeAnnotation, ignoreDecl, hasBuilder); +} + +/** + * Determine whether the node is ForEach method declaration or call expression. + * + * @param node method definition node. + * @param sourceName external source name. + */ +export function isForEach(name: string | undefined, sourceName?: string): boolean { + const externalSourceName = sourceName ?? MetaDataCollector.getInstance().externalSourceName; + return (name === InnerComponentNames.FOR_EACH || name == InnerComponentNames.FOR_EACH_IMPL) && externalSourceName === ARKUI_FOREACH_SOURCE_NAME; +} + +export class InnerComponentFunctionRecord extends BaseRecord { + private paramRecords?: ParameterRecord[]; + private typeParameters?: TypeParameterTypeRecord[]; + private hasRestParameter?: boolean; + private hasReceiver?: boolean; + private attributeName?: string; + private attributeTypeParams?: TypeRecord[]; + private hasLastTrailingLambda?: boolean; + + constructor(options: RecordOptions) { + super(options); + } + + private preprocessParam( + param: arkts.ETSParameterExpression, + index: number, + name: string + ): arkts.ETSParameterExpression { + if (index === 0 && isForEach(name) && !!param.typeAnnotation && arkts.isTypeNode(param.typeAnnotation)) { + const lambdaType = arkts.factory.createETSFunctionType( + undefined, + [], + param.typeAnnotation.clone(), + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW + ); + return arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier(param.ident!.name, lambdaType), + false, + undefined + ); + } + return param; + } + + collectFromNode(node: arkts.MethodDefinition): void { + const attributeInfo = findAttributeInfoFromComponentMethod(node); + if (!attributeInfo) { + return; + } + const name: string = node.id!.name; + const func = node.function; + const hasRestParameter = func.hasRestParameter; + const hasReceiver = func.hasReceiver; + const typeParameters = collectTypeRecordFromTypeParameterDeclaration(func.typeParams); + const params = func.params as arkts.ETSParameterExpression[]; + const paramRecords: ParameterRecord[] = []; + const hasLastTrailingLambda = checkIsTrailingLambdaInLastParam(params, this.shouldIgnoreDecl); + params.forEach((p, index) => { + if (index === params.length - 1 && hasLastTrailingLambda) { + return; + } + const record = collectTypeRecordFromParameter(this.preprocessParam(p, index, name)); + paramRecords.push(record); + }); + this.attributeName = attributeInfo.attributeName; + this.attributeTypeParams = attributeInfo.attributeTypeParams; + this.paramRecords = paramRecords; + this.typeParameters = typeParameters; + this.hasRestParameter = hasRestParameter; + this.hasReceiver = hasReceiver; + this.hasLastTrailingLambda = hasLastTrailingLambda; + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + currInfo = { + ...currInfo, + ...(this.attributeName && { attributeName: this.attributeName }), + ...(this.attributeTypeParams && { attributeTypeParams: this.attributeTypeParams }), + ...(this.paramRecords && { paramRecords: this.paramRecords }), + ...(this.typeParameters && { typeParameters: this.typeParameters }), + ...(this.hasRestParameter && { hasRestParameter: this.hasRestParameter }), + ...(this.hasReceiver && { hasReceiver: this.hasReceiver }), + ...(this.hasLastTrailingLambda && { hasLastTrailingLambda: this.hasLastTrailingLambda }), + }; + this.info = currInfo; + } + + toJSON(): InnerComponentFunctionInfo { + this.refresh(); + return { + ...(this.info?.attributeName && { attributeName: this.info.attributeName }), + ...(this.info?.attributeTypeParams && { attributeTypeParams: this.info.attributeTypeParams }), + ...(this.info?.paramRecords && { paramRecords: this.info.paramRecords }), + ...(this.info?.typeParameters && { typeParameters: this.info.typeParameters }), + ...(this.info?.hasRestParameter && { hasRestParameter: this.info.hasRestParameter }), + ...(this.info?.hasReceiver && { hasReceiver: this.info.hasReceiver }), + ...(this.info?.hasLastTrailingLambda && { hasLastTrailingLambda: this.info.hasLastTrailingLambda }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/new-class-instance.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/new-class-instance.ts new file mode 100644 index 0000000000000000000000000000000000000000..51a0aafdd5219a25ee16579bcd721a56bcfbe6d9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/new-class-instance.ts @@ -0,0 +1,71 @@ +/* + * 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 { expectNameInTypeReference } from '../../../common/arkts-utils'; +import { isDeclFromArkUI } from '../utils'; +import { BaseRecord, RecordOptions } from './base'; + +export type NewClassInstanceInfo = { + name?: string; + declName?: string; +}; + +export class NewClassInstanceRecord extends BaseRecord { + protected name?: string; + protected declName?: string; + + constructor(options: RecordOptions) { + super(options); + } + + collectFromNode(node: arkts.ETSNewClassInstanceExpression): void { + const typeRef = node.typeRef; + if (!typeRef || !arkts.isETSTypeReference(typeRef)) { + return; + } + const nameNode = expectNameInTypeReference(typeRef); + if (!nameNode) { + return; + } + const decl = arkts.getPeerIdentifierDecl(nameNode.peer); + if (!decl || !arkts.isClassDefinition(decl)) { + return; + } + if (!this.shouldIgnoreDecl && !isDeclFromArkUI(decl)) { + return; + } + this.name = nameNode.name; + this.declName = decl.ident?.name; + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + currInfo = { + ...currInfo, + ...(this.name && { name: this.name }), + ...(this.declName && { declName: this.declName }), + }; + this.info = currInfo; + } + + toJSON(): NewClassInstanceInfo { + this.refresh(); + return { + ...(this.info?.name && { name: this.info.name }), + ...(this.info?.declName && { declName: this.info.declName }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..3351928fc1726c14b71f870b710a1c8deaa90441 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class-method.ts @@ -0,0 +1,103 @@ +/* + * 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'; +import { NormalClassPropertyInfo, NormalClassPropertyRecord } from './normal-class-property'; + +export type NormalClassMethodInfo = AnnotationRecord & { + classInfo?: NormalClassInfo; + inheritPorpertyInfo?: NormalClassPropertyInfo; + 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; + private _inheritPropertyRecord?: NormalClassPropertyRecord; + + 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); + } + + withInheritPropertyRecord(propertyRecord: NormalClassPropertyRecord): this { + this._inheritPropertyRecord = propertyRecord; + return this; + } + + collectFromNode(node: arkts.MethodDefinition): void { + this.name = node.id?.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + this.isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + for (const anno of node.function.annotations) { + this._annotationRecord.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord.toRecord(); + const classRecord = this._classRecord?.toRecord(); + const inheritPorpertyInfo = this._inheritPropertyRecord?.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 }), + ...(inheritPorpertyInfo && { inheritPorpertyInfo }), + }; + this.info = currInfo; + } + + toJSON(): NormalClassMethodInfo { + this.refresh(); + const classInfo = this._classRecord?.toJSON(); + const inheritPorpertyInfo = this._inheritPropertyRecord?.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 }), + ...(inheritPorpertyInfo && { inheritPorpertyInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..923c7cbd82a8addee0773921c4ba3aa883d99e60 --- /dev/null +++ b/ui2abc/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/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..98245da0f4ce91cf8c1e08f04b69d2853782ba05 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-class.ts @@ -0,0 +1,110 @@ +/* + * 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; + + /** + * whether this class has `@Track` property. + */ + hasTrackProperty?: boolean; +}; + +export class NormalClassRecord extends BaseRecord { + private _annotationRecord: NormalClassAnnotationRecord; + + protected definitionPtr?: AstNodePointer; + protected name?: string; + protected isDecl?: boolean; + protected isETSGlobal?: boolean; + protected hasTrackProperty?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new NormalClassAnnotationRecord(options); + } + + setHasTrackProperty(hasTrackProperty: boolean): this { + this.hasTrackProperty = hasTrackProperty ?? undefined; + this.isChanged = true; + return this; + } + + 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); + } + } + + 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 }), + ...(this.hasTrackProperty && { hasTrackProperty: this.hasTrackProperty }), + ...(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.info?.isETSGlobal && { isETSGlobal: this.info.isETSGlobal }), + ...(this.info?.hasTrackProperty && { hasTrackProperty: this.info.hasTrackProperty }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-interface-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..54023418522e039ea8ef8667c40b65c3014e623d --- /dev/null +++ b/ui2abc/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.id?.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + for (const anno of node.function.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-interface.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/normal-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..4338dabe8f714797ef581737aad96527e6dd398e --- /dev/null +++ b/ui2abc/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/ui2abc/arkui-plugins/collectors/ui-collectors/records/parameter.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d2ebfcb484f4d35de2323d2d43e49d9de5ce376 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/parameter.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 { ParameterAnnotationInfo, ParameterAnnotationRecord, ParameterAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; + +export type ParameterInfo = AnnotationRecord & {}; + +export class ParameterRecord extends BaseRecord { + private _annotationRecord?: ParameterAnnotationRecord; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new ParameterAnnotationRecord(options); + } + + collectFromNode(node: arkts.ETSParameterExpression): void { + for (const anno of node.annotations) { + this._annotationRecord?.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): ParameterInfo { + this.refresh(); + return { + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/property.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ed2b6abc861fc9de48c343bc719fdacd91a70a1 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/property.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 { ArrowFunctionAnnotationInfo, ArrowFunctionAnnotationRecord, ArrowFunctionAnnotations } from './annotations'; +import { AnnotationRecord } from './annotations/base'; +import { BaseRecord, RecordOptions } from './base'; +import { RecordCache } from './cache'; + +export type PropertyInfo = AnnotationRecord & {}; + +export class PropertyRecord extends BaseRecord { + private _annotationRecord?: ArrowFunctionAnnotationRecord; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new ArrowFunctionAnnotationRecord(options); + } + + collectFromNode(node: arkts.Property): void { + const value = node.value; + if (!value || !arkts.isArrowFunctionExpression(value)) { + return; + } + // If arrow function property value is already collected, then we don't need to collect property. + if (RecordCache.getInstance().has(value.peer)) { + return; + } + for (const anno of value.annotations) { + this._annotationRecord?.collect(anno); + } + } + + refreshOnce(): void { + let currInfo = this.info ?? {}; + const annotationRecord = this._annotationRecord?.toRecord(); + currInfo = { + ...currInfo, + ...(annotationRecord && { ...annotationRecord }), + }; + this.info = currInfo; + } + + toJSON(): PropertyInfo { + this.refresh(); + return { + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/record-builder.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/record-builder.ts new file mode 100644 index 0000000000000000000000000000000000000000..513032cd8798f2d9eb509d8c68ad1ce5eadc2af4 --- /dev/null +++ b/ui2abc/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< + U extends arkts.AstNode, + V extends BaseRecord>, + 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/ui2abc/arkui-plugins/collectors/ui-collectors/records/shared-types.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/shared-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ab7e97cb881615dc6fe3d03e05cd0521596d2a3 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/shared-types.ts @@ -0,0 +1,65 @@ +/* + * 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 { ArrowFunctionInfo } from './arrow-function'; +import { FunctionInfo } from './function'; +import { CallInfo } from './function-call'; +import { NewClassInstanceInfo } from './new-class-instance'; +import { NormalClassInfo } from './normal-class'; +import { NormalClassMethodInfo } from './normal-class-method'; +import { NormalClassPropertyInfo } from './normal-class-property'; +import { NormalInterfaceInfo } from './normal-interface'; +import { NormalInterfacePropertyInfo } from './normal-interface-property'; +import { ParameterInfo } from './parameter'; +import { PropertyInfo } from './property'; +import { CustomComponentInfo } from './struct'; +import { CustomComponentInterfaceInfo } from './struct-interface'; +import { CustomComponentInterfacePropertyInfo } from './struct-interface-property'; +import { StructMethodInfo } from './struct-method'; +import { StructPropertyInfo } from './struct-property'; + +export type ClassDeclarationRecordInfo = NormalClassInfo | CustomComponentInfo; + +export type MethodDefinitionRecordInfo = + | FunctionInfo + | NormalClassMethodInfo + | StructMethodInfo + | NormalInterfacePropertyInfo + | CustomComponentInterfacePropertyInfo; + +export type ClassPropertyRecordInfo = NormalClassPropertyInfo | StructPropertyInfo; + +export type TSInterfaceDeclarationRecordInfo = NormalInterfaceInfo | CustomComponentInterfaceInfo; + +export type CallExpressionRecordInfo = CallInfo; + +export type ETSParameterExpressionRecordInfo = ParameterInfo; + +export type ArrowFunctionExpressionRecordInfo = ArrowFunctionInfo; + +export type PropertyRecordInfo = PropertyInfo; + +export type ETSNewClassInstanceExpressionRecordInfo = NewClassInstanceInfo; + +export type RecordInfo = + | MethodDefinitionRecordInfo + | ClassPropertyRecordInfo + | ClassDeclarationRecordInfo + | TSInterfaceDeclarationRecordInfo + | CallExpressionRecordInfo + | ETSParameterExpressionRecordInfo + | ArrowFunctionExpressionRecordInfo + | PropertyRecordInfo + | ETSNewClassInstanceExpressionRecordInfo; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-interface-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..921da274ad6b491d9405e56c5d6f4a07cc9c5427 --- /dev/null +++ b/ui2abc/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.id?.name; + this.modifiers = node.modifiers; + this.kind = node.kind; + for (const anno of node.function.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..4836a25a85302c5df61b4b5a5b07d880ad9495cc --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-interface.ts @@ -0,0 +1,69 @@ +/* + * 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< + arkts.TSInterfaceDeclaration, + CustomComponentInterfaceInfo +> { + 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/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-method.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..afa9991a11c728c912c9671f96388c2b78d61462 --- /dev/null +++ b/ui2abc/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.id?.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.function.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/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-property.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0f554b75a2f28299a582a128ae08131fc853081 --- /dev/null +++ b/ui2abc/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/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ae70a248b0b88833fe38840df7d7631d67c983c --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/records/struct.ts @@ -0,0 +1,127 @@ +/* + * 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 { checkIsCustomComponentDeclaredClassFromInfo, 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 struct or declared `CustomComponent` is from ArkUI SDK. + */ + isFromArkUI?: boolean; + + /** + * whether this struct or `CustomComponent` class is declared. + */ + isDecl?: boolean; + + /** + * whether this struct is from legacy application. + */ + isLegacy?: boolean; +}; + +export class CustomComponentRecord extends BaseRecord { + private _annotationRecord: CustomComponentAnnotationRecord; + + protected definitionPtr?: AstNodePointer; + protected name?: string; + protected isDecl?: boolean; + protected isFromArkUI?: boolean; + protected isLegacy?: boolean; + + constructor(options: RecordOptions) { + super(options); + this._annotationRecord = new CustomComponentAnnotationRecord(options); + } + + withIsFromArkUI(isFromArkUI: boolean): this { + this.isFromArkUI = isFromArkUI; + return this; + } + + collectFromNode(node: arkts.ClassDeclaration): void { + const definition: arkts.ClassDefinition | undefined = node.definition; + if (!definition) { + return; + } + const name = definition.ident?.name; + if (!name) { + return; + } + const isDecl = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + const isLegacy = definition.language === arkts.Es2pandaLanguage.LANGUAGE_JS; + const isStruct = checkIsStructFromNode(node, !isLegacy); + const isCustomComponentClass = checkIsCustomComponentDeclaredClassFromInfo({ + name, + isDecl, + isFromArkUI: this.isFromArkUI, + }); + if (!isStruct && !isCustomComponentClass) { + return; + } + this.name = name; + this.isDecl = isDecl; + if (isStruct) { + for (const anno of definition.annotations) { + this._annotationRecord.collect(anno); + } + this.definitionPtr = definition.peer; + this.isLegacy = isLegacy; + 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.isFromArkUI && { isFromArkUI: this.isFromArkUI }), + ...(this.isLegacy && { isLegacy: this.isLegacy }), + ...(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?.isFromArkUI && { isFromArkUI: this.info.isFromArkUI }), + ...(this.info?.isLegacy && { isLegacy: this.info.isLegacy }), + ...(this.info?.annotationInfo && { annotationInfo: this.info.annotationInfo }), + }; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/shared-types.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/shared-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..dab033c960ffca2af49ff373f42628c74413cb08 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/shared-types.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 { VisitorOptions } from '../../common/abstract-visitor'; +import { AstNodePointer } from '../../common/safe-types'; +import { CallRecord, CustomComponentInfo, StructMethodInfo, StructPropertyInfo } from './records'; + +export interface UICollectMetadata extends VisitorOptions { + shouldIgnoreDecl: boolean; +} + +export interface StructCollectorInfo extends CustomComponentInfo { + propertyInfoMap: Map; + methodInfoMap: Map; +} + +export interface CallRecordInfo { + call: arkts.CallExpression; + callRecord: CallRecord; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/struct-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/struct-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..660a5352eb0d1c09d9090ce7ee05d92c218eddb5 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/struct-collector.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 { + 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'; +import { checkIsCustomComponentFromInfo } from './utils'; +import { NodeCacheFactory } from '../../common/node-cache'; + +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; + } + + 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.structInfo && checkIsCustomComponentFromInfo(info.structInfo) && 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; + } + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, propertyRecord.toJSON()); + 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; + } + if (this.canCollectMethodFromInfo(methodInfo)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + } + 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/ui2abc/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts new file mode 100644 index 0000000000000000000000000000000000000000..34dda1709d6ed81460cda905820d4ece89363cc8 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/struct-interface-collector.ts @@ -0,0 +1,72 @@ +/* + * 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'; +import { NodeCacheFactory } from '../../common/node-cache'; + +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)) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).collect(node, methodRecord.toJSON()); + } + } + + visitor(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + node.body?.body.forEach((st) => { + if (arkts.isMethodDefinition(st)) { + this.collectMethod(st); + } + }); + return node; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/ui-visitor.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/ui-visitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..526f6d268def491a39abdff33b0a5d529565b8a4 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/ui-visitor.ts @@ -0,0 +1,84 @@ +/* + * 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'; +import { matchPrefix } from '../../common/arkts-utils'; +import { LINTER_EXCLUDE_EXTERNAL_SOURCE_PREFIXES } from '../../common/predefines'; +import { MetaDataCollector } from '../../common/metadata-collector'; + +export interface UIVisitorOptions extends VisitorOptions { + shouldIgnoreDecl?: boolean; + shouldCheckUISyntax?: boolean; +} + +export class UIVisitor extends AbstractVisitor { + private _shouldIgnoreDecl?: boolean; + private _shouldCheckUISyntax?: boolean; + + constructor(options?: UIVisitorOptions) { + super(options); + this._shouldIgnoreDecl = options?.shouldIgnoreDecl; + this._shouldCheckUISyntax = options?.shouldCheckUISyntax; + } + + get shouldIgnoreDecl(): boolean { + return this._shouldIgnoreDecl ?? false; + } + + get shouldCheckUISyntax(): boolean { + return this._shouldCheckUISyntax ?? false; + } + + init(): void { + super.init(); + ValidatorBuilder.shouldSkip = + !!this.shouldCheckUISyntax && !!this.externalSourceName + ? matchPrefix(LINTER_EXCLUDE_EXTERNAL_SOURCE_PREFIXES, this.externalSourceName) + : true; + MetaDataCollector.getInstance().setExternalSourceName(this.externalSourceName); + } + + reset(): void { + super.reset(); + CallRecordCollector.getInstance(this.getMetadata()).reset(); + if (this.shouldCheckUISyntax) { + ValidatorBuilder.reset(); + LogCollector.getInstance().emitLogInfo(); + LogCollector.getInstance().reset(); + } + } + + getMetadata(): UICollectMetadata { + return { + isExternal: this.isExternal, + externalSourceName: this.externalSourceName, + program: this.program, + shouldIgnoreDecl: this.shouldIgnoreDecl, + }; + } + + visitor(node: arkts.AstNode): arkts.AstNode { + findAndCollectUINodeInPreOrder(node, this.getMetadata()); + const newNode = this.visitEachChild(node); + findAndCollectUINodeInPostOrder(newNode, this.getMetadata()); + return newNode; + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/utils.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..24717b04e199ffe1f3931fa98f9a1498b75b644b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/utils.ts @@ -0,0 +1,403 @@ +/* + * 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 { filterDefined, matchPrefix } from '../../common/arkts-utils'; +import { DeclarationCollector } from '../../common/declaration-collector'; +import { + CustomComponentNames, + ARKUI_IMPORT_PREFIX_NAMES, + BuiltInNames, + BuilderLambdaNames, + Dollars, + StateManagementTypes, + ARKUI_BUILDER_SOURCE_NAME, + DecoratorNames, + InnerComponentNames, + InnerComponentAttributes, + GetSetTypes, + CustomDialogNames, +} from '../../common/predefines'; +import { + ArrowFunctionInfo, + CallDeclInfo, + CallInfo, + CustomComponentInfo, + CustomComponentInterfaceInfo, + CustomComponentInterfacePropertyInfo, + FunctionInfo, + NewClassInstanceInfo, + NormalClassInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + NormalInterfaceInfo, + NormalInterfacePropertyInfo, + ParameterInfo, + RecordInfo, + StructMethodInfo, + StructPropertyInfo, +} from './records'; +import { AnnotationInfo, Annotations } from './records/annotations/base'; + +export function checkCanCollectNormalClassFromInfo(info: NormalClassInfo, externalSourceName?: string): boolean { + if (checkIsObservedClassFromInfo(info)) { + return true; + } + if (externalSourceName === ARKUI_BUILDER_SOURCE_NAME && checkIsETSGlobalClassFromInfo(info)) { + return true; + } + return false; +} + +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; + } + const expr: arkts.Identifier = anno.expr; + const name: string = expr.name; + const whiteList: string[] = getNonArkUIAnnotationWhiteList(); + if (whiteList.includes(name)) { + return name; + } + const decl = arkts.getPeerIdentifierDecl(expr.peer); + if (!decl) { + return undefined; + } + if (!ignoreDecl && !isDeclFromArkUI(decl)) { + return undefined; + } + return name; +} + +export function getNonArkUIAnnotationWhiteList(): string[] { + return [DecoratorNames.JSONSTRINGIFYIGNORE, DecoratorNames.JSONRENAME]; +} + +export function getArkUIAnnotationNames( + annotations: Annotations | undefined, + info: AnnotationInfo | undefined +): string[] { + if (!annotations || !info) { + return []; + } + const keys = Object.keys(info); + if (keys.length === 0) { + return []; + } + const whiteList: string[] = getNonArkUIAnnotationWhiteList(); + let filteredList: string[] = []; + Object.keys(annotations).forEach((name, idx) => { + if (whiteList.includes(name) || !keys.at(idx)) { + return; + } + filteredList.push(keys.at(idx)!); + }); + return filteredList; +} + +export function isDeclFromArkUI( + decl: arkts.AstNode, + matchSourcePrefix: (string | RegExp)[] = ARKUI_IMPORT_PREFIX_NAMES +): arkts.AstNode | undefined { + const moduleName: string | undefined = arkts.getProgramFromAstNode(decl)?.moduleName; + if (!moduleName || !matchPrefix(matchSourcePrefix, moduleName)) { + return undefined; + } + DeclarationCollector.getInstance().collect(decl); + return decl; +} + +export function formatBuiltInInheritPropertyName(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) || !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 checkIsCallNameFromForEach(name: string): name is InnerComponentNames.FOR_EACH { + return name === InnerComponentNames.FOR_EACH; +} + +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, shouldFindStructFlag?: boolean): boolean { + if (arkts.isETSStructDeclaration(node)) { + return true; + } + if (arkts.isClassDeclaration(node) && !!node.definition) { + if (!!shouldFindStructFlag) { + return node.definition.isFromStruct; + } + return true; + } + return false; +} + +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.name || !info.isDecl || !info.isFromArkUI) { + return false; + } + return ( + info.name === CustomComponentNames.COMPONENT_CLASS_NAME || + info.name === CustomComponentNames.COMPONENT_V2_CLASS_NAME || + info.name === CustomComponentNames.BASE_CUSTOM_DIALOG_NAME + ); +} + +export function checkIsObservedClassFromInfo(info: NormalClassInfo | undefined): boolean { + const annotationInfo = info?.annotationInfo ?? {}; + return !!annotationInfo.hasObserved || !!annotationInfo.hasObservedV2; +} + +export function checkIsNormalClassHasTrackProperty(info: NormalClassInfo | undefined): boolean { + return !!info?.hasTrackProperty; +} + +export function checkIsETSGlobalClassFromInfo(info: NormalClassInfo | undefined): boolean { + return !!info?.isETSGlobal; +} + +export function checkIsCommonMethodInterfaceFromInfo(info: NormalInterfaceInfo | undefined): boolean { + return info?.name === InnerComponentAttributes.COMMON_METHOD; +} + +export function checkIsComponentAttributeInterfaceFromInfo(info: NormalInterfaceInfo | undefined): boolean { + if (!info?.name) { + return false; + } + const regex: RegExp = /(?\w+Attribute)(?:<.*>)?$/; + const match: RegExpExecArray | null = regex.exec(info.name); + const attributeName: string | undefined = match?.groups?.source; + return !!attributeName; +} + +export function checkIsBuilderFromInfo( + info: ParameterInfo | ArrowFunctionInfo | NormalClassPropertyInfo | StructPropertyInfo | CallDeclInfo | undefined +): boolean { + return !!info?.annotationInfo?.hasBuilder; +} + +export function checkIsBuilderLambdaMethodDeclFromInfo(metadata: StructMethodInfo | FunctionInfo): boolean { + const isStructMethod = checkIsStructMethodFromInfo(metadata); + let isBuilderLambda: boolean = !!metadata.annotationInfo?.hasComponentBuilder; + if (isStructMethod) { + isBuilderLambda &&= + checkIsCustomComponentDeclaredClassFromInfo(metadata.structInfo) && + metadata.name === BuilderLambdaNames.ORIGIN_METHOD_NAME; + } + const isMethodDecl: boolean = !!metadata.isDecl; + return isBuilderLambda && isMethodDecl; +} + +export function checkIsBuilderLambdaFunctionCallFromInfo(info: StructMethodInfo): boolean { + if (!info.name) { + return false; + } + return ( + info.name !== BuilderLambdaNames.ORIGIN_METHOD_NAME && info.name !== BuilderLambdaNames.TRANSFORM_METHOD_NAME + ); +} + +export function checkIsStructMethodFromInfo(info: RecordInfo): info is StructMethodInfo { + return Object.hasOwn(info, 'structInfo'); +} + +export function getGetterSetterTypeFromInfo(metadata: NormalClassMethodInfo): GetSetTypes | undefined { + switch (metadata.kind) { + case arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET: + return GetSetTypes.GET; + case arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET: + return GetSetTypes.SET; + } + return undefined; +} + +export function checkIsObservedImplementsMethod(metadata: NormalClassMethodInfo): boolean { + const needObservedTransform = + !!metadata.classInfo?.annotationInfo?.hasObserved || !!metadata.inheritPorpertyInfo?.annotationInfo?.hasTrack; + return needObservedTransform; +} + +export function checkIsObservedV2ImplementsMethod(metadata: NormalClassMethodInfo): boolean { + const needObservedTransform = + !!metadata.classInfo?.annotationInfo?.hasObservedV2 || !!metadata.inheritPorpertyInfo?.annotationInfo?.hasTrace; + return needObservedTransform; +} + +export function checkIsCustomComponentClassFromInfo(info: CustomComponentInfo): boolean { + return checkIsCustomComponentFromInfo(info) || checkIsCustomComponentDeclaredClassFromInfo(info); +} + +export function checkIsGlobalFunctionFromInfo(info: FunctionInfo): boolean { + return ( + !Object.hasOwn(info, 'classInfo') && !Object.hasOwn(info, 'structInfo') && !Object.hasOwn(info, 'interfaceInfo') + ); +} + +export function checkIsNormalClassMethodFromInfo(info: NormalClassMethodInfo): boolean { + return Object.hasOwn(info, 'classInfo'); +} + +export function checkIsStructInterfacePropertyFromInfo(info: CustomComponentInterfacePropertyInfo): boolean { + if (!Object.hasOwn(info, 'interfaceInfo')) { + return false; + } + return checkIsCustomComponentFromInfo(info.interfaceInfo); +} + +export function checkIsNormalInterfacePropertyFromInfo(info: NormalInterfacePropertyInfo): boolean { + return Object.hasOwn(info, 'interfaceInfo'); +} + +export function checkIsResourceFromInfo(metadata: CallInfo): boolean { + return !!metadata.isResourceCall; +} + +export function checkIsStructPropertyFromInfo(info: StructPropertyInfo): boolean { + return Object.hasOwn(info, 'structInfo'); +} + +export function checkIsNormalClassPropertyFromInfo(info: NormalClassPropertyInfo): boolean { + return Object.hasOwn(info, 'classInfo'); +} + +export function checkIsBuilderLambdaFromInfo(metadata: CallInfo): boolean { + const rootCallInfo: CallInfo | undefined = metadata.rootCallInfo ?? metadata; + if (!rootCallInfo) { + return false; + } + return !!rootCallInfo.annotationInfo?.hasComponentBuilder; +} + +export function checkIsFunctionMethodDeclFromInfo(metadata: StructMethodInfo | FunctionInfo): metadata is FunctionInfo { + return ( + !!metadata.isDecl && + Object.hasOwn(metadata, 'innerComponentInfo') && + !!(metadata as FunctionInfo).innerComponentInfo + ); +} + +export function checkIsMonitorMethodFromInfo(metadata: StructMethodInfo | NormalClassMethodInfo): boolean { + return !!metadata.annotationInfo?.hasMonitor; +} + +export function checkIsComputedMethodFromInfo(metadata: StructMethodInfo | NormalClassMethodInfo): boolean { + return !!metadata.annotationInfo?.hasComputed; +} + +export function checkIsDialogControllerNewInstanceFromInfo(metadata: NewClassInstanceInfo | undefined): boolean { + return metadata?.declName === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER; +} + +export function checkIsAnimatableExtendMethodFromInfo(metadata: FunctionInfo): boolean { + return !!metadata.annotationInfo?.hasAnimatableExtend; +} + +export function checkIsCallFromLegacyBuilderFromInfo(metadata: CallInfo): boolean { + if (!metadata.isDeclFromLegacy) { + return false; + } + return !!metadata.annotationInfo?.hasBuilder || !!metadata.ignoredAnnotationInfo?.hasMemo; +} + +export function checkIsInteropComponentCallFromInfo(metadata: CallInfo): boolean { + return !!metadata.structDeclInfo?.isLegacy; +} + +export function checkIsCustomDialogControllerBuilderOptionsFromInfo(metadata: NormalInterfacePropertyInfo): boolean { + return ( + metadata.interfaceInfo?.name === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER_OPTIONS && + metadata.name === CustomDialogNames.OPTIONS_BUILDER + ); +} + +export function collectStructPropertyInfos(metadata: CallInfo): CustomComponentInterfacePropertyInfo[] { + if (!metadata.structPropertyInfos) { + return []; + } + return filterDefined(metadata.structPropertyInfos.map((info) => info[1])); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/base.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/base.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ba49d5505f2ca6003611448d03fccc0a69d7c20 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/base.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 { LogCollector, LogInfo, SuggestionOptions } from '../../../common/log-collector'; + +export interface Validator { + checkIsViolated(node: TargetNode, metadata?: ContextMetadata): void; + collectContext(context: ContextMetadata): this; + withShouldSkip(shouldSkip?: boolean): this; + reset(): void; +} + +export abstract class BaseValidator implements Validator { + protected context?: R; + protected shouldSkip: boolean; + + constructor() { + this.shouldSkip = false; + } + + withShouldSkip(shouldSkip?: boolean): this { + if (!!shouldSkip) { + this.shouldSkip = shouldSkip; + } + return this; + } + + reset(): void { + this.context = undefined; + } + + checkIsViolated(node: T, metadata?: R | undefined): void { + if (this.shouldSkip) { + return; + } + if (!!metadata) { + this.collectContext(metadata); + } + this.reportIfViolated(node); + } + + collectContext(context: R): this { + this.context = context; + return this; + } + + protected report(logInfo: LogInfo): void { + LogCollector.getInstance().collectLogInfo(logInfo); + } + + abstract reportIfViolated(node: T): void; +} + +/** + * Reformat `logInfo` into serializable JSON object. This is only used for debugging purpose. + * + * @internal + */ +export function formatReport(logInfo: LogInfo): Object | undefined { + const node = logInfo.node.dumpSrc(); + return { + node, + level: logInfo.level, + message: logInfo.message, + args: logInfo.args, + suggestion: formatSuggestion(logInfo.suggestion), + code: logInfo.code, + }; +} + +/** + * Reformat `suggestion` into serializable JSON object. This is only used for debugging purpose. + * + * @internal + */ +export function formatSuggestion(suggestion: SuggestionOptions | undefined): Object | undefined { + if (!suggestion) { + return undefined; + } + const startRange = `(${suggestion.range[0].getIndex()}, ${suggestion.range[0].getLine()})`; + const endRange = `(${suggestion.range[1].getIndex()}, ${suggestion.range[1].getLine()})`; + const range = `${startRange} - ${endRange}`; + return { code: suggestion.code, range, title: suggestion.title, args: suggestion.args }; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/cache.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/cache.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1baae1f4037cd1a7478cc5b42f84b5cc44b3453 --- /dev/null +++ b/ui2abc/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, shouldSkip?: boolean): Validator { + if (cache.has(key)) { + return cache.get(key)!.withShouldSkip(shouldSkip); + } + + const newValidator = create().withShouldSkip(shouldSkip); + cache.set(key, newValidator); + return newValidator; +} + +export function clearValidatorCache(): void { + Array.from(cache.values()).forEach((validator) => validator.reset()); + cache.clear(); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/call-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/call-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..ead913d040fe39dfaf408f0caca2bddcd5eeac3f --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/call-validator.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 { BaseValidator } from './base'; +import { + checkBuilderParam, + checkComponentV2StateUsage, + checkComputedDecorator, + checkConsumerProviderDecorator, + checkComponentComponentV2Init, + checkConstructPrivateParameter, + checkReusableComponentInV2, + checkNestedReuseComponent, + checkConstructParameter, + checkSpecificComponentChildren, + checkConstructParameterLiteral, + checkVariableInitializationPassing, + checkReuseAttribute, + checkWrapBuilder, + checkUIConsistent, + checkAttributeNoInvoke, + checkNestedRelationship, + checkNoChildInButton, + checkStaticParamRequire, + checkNoDuplicateId, + resetNoDuplicateId, +} from './rules'; +import { CallInfo } from '../records'; +import { checkIsCustomComponentFromInfo } from '../utils'; + +export class CallValidator extends BaseValidator { + reset(): void { + super.reset(); + resetNoDuplicateId(); + } + + reportIfViolated(node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + checkNoDuplicateId.bind(this)(node); + if (!checkIsCustomComponentFromInfo(metadata.structDeclInfo) || !metadata.structDeclInfo?.definitionPtr) { + reportInNonStructCall.bind(this)(node, metadata); + return; + } + reportInStructCall.bind(this)(node, metadata); + } +} + +/** + * 只处理自定义组件 CallExpression的场景 + */ +function reportInStructCall(this: CallValidator, node: arkts.CallExpression, metadata: CallInfo): void { + checkComponentV2StateUsage.bind(this)(node); + checkComputedDecorator.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); + checkConstructParameterLiteral.bind(this)(node); + checkConstructParameter.bind(this)(node); + checkReuseAttribute.bind(this)(node); + checkAttributeNoInvoke.bind(this)(node); + + const struct = arkts.unpackNonNullableNode(metadata.structDeclInfo!.definitionPtr!); + checkBuilderParam.bind(this)(node, struct); + checkComponentComponentV2Init.bind(this)(node, struct); + checkReusableComponentInV2.bind(this)(struct); + checkNestedReuseComponent.bind(this)(struct); + checkConstructPrivateParameter.bind(this)(struct); + checkStaticParamRequire.bind(this)(struct); + checkVariableInitializationPassing.bind(this)(node, struct); +} + +/** + * 只处理*非*自定义组件 CallExpression的场景 + */ +function reportInNonStructCall(this: CallValidator, node: arkts.CallExpression, metadata: CallInfo): void { + checkSpecificComponentChildren.bind(this)(node); + checkWrapBuilder.bind(this)(node); + checkUIConsistent.bind(this)(node); + checkAttributeNoInvoke.bind(this)(node); + checkNestedRelationship.bind(this)(node); + checkNoChildInButton.bind(this)(node); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/function-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/function-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..9acdbe372ec43557e58580fe5b1f62a3fa77b863 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/function-validator.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 * as arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { FunctionInfo } from '../records'; +import { + checkObservedV2TraceUsageValidation, + checkOneDecoratorOnFunctionMethod, + checkTrackDecorator, + checkValidateDecoratorTarget, + checkComponentV2StateUsage, +} from './rules'; + +export class FunctionValidator extends BaseValidator { + reportIfViolated(node: arkts.MethodDefinition): void { + checkOneDecoratorOnFunctionMethod.bind(this)(node); + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkComponentV2StateUsage.bind(this)(node); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/global-property-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/global-property-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..3af97007cedeeb45848a968a4a3582a3511a4488 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/global-property-validator.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 * as arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { GLobalPropertyInfo } from '../records'; +import { checkTrackDecorator, checkObservedV2TraceUsageValidation, checkValidateDecoratorTarget } from './rules'; + +export class GlobalPropertyValidator extends BaseValidator { + reportIfViolated(node: arkts.ClassProperty): void { + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/index.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..dcc88636bc4a97d5accdfb8b0b038a1a32d18310 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/index.ts @@ -0,0 +1,26 @@ +/* + * 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 './call-validator'; +export * from './struct-validator'; +export * from './struct-property-validator'; +export * from './struct-method-validator'; +export * from './normal-class-validator'; +export * from './normal-class-method-validator'; +export * from './normal-class-property-validator'; +export * from './normal-interface-validator'; +export * from './global-property-validator'; +export * from './function-validator'; +export * from './validator-builder'; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4db32205fe88430bc61ed74e1388efce9af45d7 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-method-validator.ts @@ -0,0 +1,50 @@ +/* + * 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, + checkMonitorDecorator, + checkObservedV2TraceUsageValidation, + checkOnceDecorator, + checkStructPropertyDecorator, + checkTrackDecorator, + checkValidateDecoratorTarget, + checkComponentV2StateUsage, +} 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); + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkOnceDecorator.bind(this)(node); + checkStructPropertyDecorator.bind(this)(node); + checkMonitorDecorator.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkComponentV2StateUsage.bind(this)(node); + + const classNode = arkts.unpackNode(metadata.classInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, classNode); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..76fabc8b000eea003a0a3ee9d9a480e06f6daa79 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-property-validator.ts @@ -0,0 +1,48 @@ +/* + * 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, + checkMonitorDecorator, + checkObservedV2TraceUsageValidation, + checkOnceDecorator, + checkTrackDecorator, + checkValidateDecoratorTarget, + checkOldNewDecoratorMixUse, +} 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); + checkOnceDecorator.bind(this)(node); + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkMonitorDecorator.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkOldNewDecoratorMixUse.bind(this)(node); + + const classNode = arkts.unpackNode(metadata.classInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, classNode); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbee824e7f937befcee8ebeb63ad8dc7f9a33bf2 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-class-validator.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 { NormalClassInfo } from '../records'; +import { + checkObservedHeritageCompatible, + checkObservedObservedV2, + checkObservedV2TraceUsageValidation, + checkValidateDecoratorTarget, + checkComponentV2StateUsage, + checkConsumerProviderDecorator, +} from './rules'; + +export class NormalClassValidator extends BaseValidator { + reportIfViolated(node: arkts.ClassDeclaration): void { + const metadata = this.context ?? {}; + if (!!metadata.isETSGlobal) { + reportInETSGlobalClass.bind(this)(node, metadata); + return; + } + reportInNormalClass.bind(this)(node, metadata); + } +} + +/** + * 只处理ETSGLOBAL ClassDeclaration + */ +function reportInETSGlobalClass( + this: NormalClassValidator, + node: arkts.ClassDeclaration, + metadata: NormalClassInfo +): void { +} + +/** + * 只处理用户定义的 ClassDeclaration + */ +function reportInNormalClass( + this: NormalClassValidator, + node: arkts.ClassDeclaration, + metadata: NormalClassInfo +): void { + checkObservedObservedV2.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkObservedHeritageCompatible.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkComponentV2StateUsage.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-interface-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-interface-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1b7395d392c1aaae3675a120a92f440da1e9c08 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/normal-interface-validator.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 * as arkts from '@koalaui/libarkts'; +import { BaseValidator } from './base'; +import { NormalInterfaceInfo } from '../records'; +import { checkObservedV2TraceUsageValidation, checkTrackDecorator, checkValidateDecoratorTarget } from './rules'; + +export class NormalInterfaceValidator extends BaseValidator { + reportIfViolated(node: arkts.TSInterfaceDeclaration): void { + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-attribute-no-invoke.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-attribute-no-invoke.ts new file mode 100644 index 0000000000000000000000000000000000000000..571c820525720414fd45c26c87b4b36302370105 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-attribute-no-invoke.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 { BaseValidator } from '../base'; +import { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { checkIsBuilderLambdaFromInfo } from '../../utils'; + +export const checkAttributeNoInvoke = performanceLog( + _checkAttributeNoInvoke, + getPerfName([0, 0, 0, 0, 0], 'checkAttributeNoInvoke') +); + +/** + * 校验规则:用于验证组件是否符合UI 组件语法要求 + * 1. 组件属性括号不能遗漏(只检验链式属性中最后一个属性的括号) + * + * 校验等级:error + */ +function _checkAttributeNoInvoke( + this: BaseValidator, + node: arkts.CallExpression +): void { + const metadata = this.context ?? {}; + metadata.rootCallInfo?.annotationInfo?.hasComponentBuilder; + if (!checkIsBuilderLambdaFromInfo(metadata)) { + return; + } + + const parent = node.parent; + if (!parent || !arkts.isMemberExpression(parent)) { + return; + } + + const grandParent = parent.parent; + // 组件属性括号不能遗漏(只检验链式属性中最后一个属性的括号) + if (!!grandParent && arkts.isExpressionStatement(grandParent)) { + this.report({ + node: parent, + level: LogType.ERROR, + message: `'${parent.dumpSrc()}' does not meet UI component syntax.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-build-root-node.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-build-root-node.ts new file mode 100644 index 0000000000000000000000000000000000000000..32776b92c99c20fdee93782ee617dc48aa87db90 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-build-root-node.ts @@ -0,0 +1,137 @@ +/* + * 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 { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { MetaDataCollector } from '../../../../common/metadata-collector'; +import { UIComponents } from '../../../../common/plugin-context'; + +export const checkBuildRootNode = performanceLog( + _checkBuildRootNode, + getPerfName([0, 0, 0, 0, 0], 'checkBuildRootNode') +); + +const BUILD_NAME = 'build'; +const BUILD_COUNT_LIMIT: number = 1; +const INVALID_ENTRY_BUILD_ROOT = `In an '@Entry' decorated component, the 'build' function can have only one root node, which must be a container component.`; +const INVALID_BUILD_ROOT = `The 'build' function can have only one root node.`; + +/** + * 校验规则:用于验证组件中 `build()` 方法的结构是否符合规范。 + * 1. 组件的 `build()` 方法必须只包含一个根节点。 + * 2. 如果组件被 `@Entry` 装饰器修饰: + * - `build()` 方法中必须只有一个根节点; + * - 该根节点必须是一个容器组件(如:`Column`, `Row`, `Stack`, `Scroll` 等)。 + * 3. `build()`内使用`console.log()`或`hilog.info()`,打印日志的方法不被计算为根节点。 + * + * 校验等级:error + */ +function _checkBuildRootNode( + this: BaseValidator, + node: arkts.MethodDefinition +): void { + const metadata = this.context ?? {}; + const hasEntryInStruct = !!metadata.structInfo?.annotationInfo?.hasEntry; + + if (metadata.name !== BUILD_NAME) { + return; + } + const blockStatement = node.function.body; + const buildNode = node.function.id; + if (!blockStatement || !arkts.isBlockStatement(blockStatement) || !buildNode) { + return; + } + const statements = blockStatement.statements; + const rootNodeNames: string[] = []; + const componentsInfo = MetaDataCollector.getInstance().componentsInfo; + recordRootNode.bind(this)(statements, rootNodeNames, componentsInfo); + if (rootNodeNames.length > BUILD_COUNT_LIMIT) { + this.report({ + node: node, + level: LogType.ERROR, + message: hasEntryInStruct ? INVALID_ENTRY_BUILD_ROOT : INVALID_BUILD_ROOT, + }); + } else if (rootNodeNames.length === BUILD_COUNT_LIMIT && hasEntryInStruct) { + validateContainerInBuild.bind(this)(buildNode, rootNodeNames, componentsInfo); + } +} + +function recordRootNode( + this: BaseValidator, + statements: readonly arkts.Statement[], + rootNodeNames: string[], + componentsInfo?: UIComponents +): void { + statements.forEach((statement) => { + if (!arkts.isExpressionStatement(statement)) { + return; + } + if (!statement.expression) { + return; + } + const componentName = getComponentName(statement.expression); + if (!componentName) { + return; + } + const isBuiltInComponent = + componentsInfo?.atomicComponents.includes(componentName) || + componentsInfo?.containerComponents.includes(componentName); + if (isBuiltInComponent) { + rootNodeNames.push(componentName); + } + }); +} + +function validateContainerInBuild( + this: BaseValidator, + buildNode: arkts.Identifier, + rootNodeNames: string[], + componentsInfo?: UIComponents +): void { + const componentName = rootNodeNames[0]; + let isContainer = componentsInfo?.containerComponents.includes(componentName); + if (!isContainer) { + this.report({ + node: buildNode, + level: LogType.ERROR, + message: INVALID_ENTRY_BUILD_ROOT, + }); + } +} + +function getComponentName(node: arkts.AstNode): string | undefined { + let children = node.getChildren(); + let componentName: string | undefined; + + while (true) { + if (!children || children.length === 0) { + return undefined; + } + + const firstChild = children[0]; + if (arkts.isIdentifier(firstChild)) { + componentName = firstChild.name; + return componentName; + } + + if (!arkts.isMemberExpression(firstChild) && !arkts.isCallExpression(firstChild)) { + return undefined; + } + children = firstChild.getChildren(); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts new file mode 100644 index 0000000000000000000000000000000000000000..67545ee283131bcae054155581e6b273fd7b000b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-builder-param.ts @@ -0,0 +1,67 @@ +/* + * 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 { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkBuilderParam = performanceLog(_checkBuilderParam, getPerfName([0, 0, 0, 0, 0], 'checkBuilderParam')); + +/** + * 校验规则:自定义组件尾随闭包调用的场景,struct 声明中有且只能有1个BuilderParam + * + * 校验等级:error + */ +function _checkBuilderParam( + this: BaseValidator, + call: arkts.CallExpression, + 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: call, // 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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-init.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-init.ts new file mode 100644 index 0000000000000000000000000000000000000000..991d963a2e3896bbbc9a00fd66f864e3ac90e2dc --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-init.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 { isAnnotatedProperty } from '../utils'; +import { CallInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkComponentComponentV2Init = performanceLog( + _checkComponentComponentV2Init, + getPerfName([0, 0, 0, 0, 0], 'checkComponentComponentV2Init') +); + +/** + * 校验规则:当V2组件使用V1组件时,V1组件中不允许存在被`@Link`装饰的属性 + * + * 校验等级:error + */ +function _checkComponentComponentV2Init( + this: BaseValidator, + node: arkts.CallExpression, + 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)) { + this.report({ + node: node, + level: LogType.ERROR, + message: `A V2 component cannot be used with any member property annotated by '@Link' in a V1 component.`, + suggestion: createSuggestion(``, ...getPositionRangeFromNode(node), `Remove the component`), + }); + } + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-mix-use.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-mix-use.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d70c0162fae93ba05ce9f6503d5f3edc7b07cfd --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-componentV2-mix-use.ts @@ -0,0 +1,141 @@ +/* + * 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'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkComponentComponentV2MixUse = performanceLog( + _checkComponentComponentV2MixUse, + getPerfName([0, 0, 0, 0, 0], 'checkComponentComponentV2MixUse') +); + +/** + * 校验规则:禁止在`@Component`中使用`@ObservedV2`装饰的类 + * + * 校验等级:error + */ +function _checkComponentComponentV2MixUse( + 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.typeRef); + } + if (!!expr) { + decl = arkts.getPeerIdentifierDecl(expr.peer); + } + if (!decl || !checkIsClassDef(decl) || !checkIsClassDecl(decl.parent)) { + return; + } + const classRecord = RecordBuilder.build(NormalClassRecord, decl.parent, { shouldIgnoreDecl: 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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-link-init.ts new file mode 100644 index 0000000000000000000000000000000000000000..b22387aa2765add0e93c4ccfecab327d8d3f3057 --- /dev/null +++ b/ui2abc/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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-component-v2-mix-use.ts new file mode 100644 index 0000000000000000000000000000000000000000..78838e2c7edd09220f5909170b70b46724e13e4c --- /dev/null +++ b/ui2abc/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.typeRef); + } + if (!!expr) { + decl = arkts.getPeerIdentifierDecl(expr.peer); + } + if (!decl || !checkIsClassDef(decl) || !checkIsClassDecl(decl.parent)) { + return; + } + const classRecord = RecordBuilder.build(NormalClassRecord, decl.parent, { shouldIgnoreDecl: 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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-mix.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-mix.ts new file mode 100644 index 0000000000000000000000000000000000000000..985cc11194383cd048c68b8ac61747a78d875173 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-mix.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 { BaseValidator } from '../base'; +import { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkComponentV2Mix = performanceLog( + _checkComponentV2Mix, + getPerfName([0, 0, 0, 0, 0], 'checkComponentV2Mix') +); + +/** + * 校验规则:用于验证 `struct` 结构体中是否正确使用了`@ComponentV2`组件装饰器 + * 1. `struct` 被 `@ComponentV2` 修饰时,无法再用`@Component`、`@Reusable` 或 `@CustomDialog`修饰 + * + * 校验等级:error + */ +function _checkComponentV2Mix( + this: BaseValidator, + struct: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const hasComponentV2 = !!metadata.annotationInfo?.hasComponentV2; + const hasComponent = !!metadata.annotationInfo?.hasComponent; + const hasReusable = !!metadata.annotationInfo?.hasReusable; + const hasCustomDialog = !!metadata.annotationInfo?.hasCustomDialog; + // `struct` 被 `@ComponentV2` 修饰时,无法再用`@Component`、`@Reusable` 或 `@CustomDialog`修饰 + if (hasComponentV2 && (hasComponent || hasReusable || hasCustomDialog)) { + if (!struct.definition || !struct.definition.ident) { + return; + } + this.report({ + node: struct.definition.ident, + level: LogType.ERROR, + message: `The struct '${metadata.name}' can not be decorated with '@ComponentV2' and '@Component', '@Reusable', '@CustomDialog' at the same time.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts new file mode 100644 index 0000000000000000000000000000000000000000..e391ac60388eb9ee1fecccbc19f3af81d5221901 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-componentV2-state-usage.ts @@ -0,0 +1,227 @@ +/* + * 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 } from '../safe-types'; +import { + CallInfo, + StructMethodInfo, + StructPropertyInfo, + FunctionInfo, + NormalClassMethodInfo, + NormalClassInfo, +} from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkComponentV2StateUsage = performanceLog( + _checkComponentV2StateUsage, + getPerfName([0, 0, 0, 0, 0], 'checkComponentV2StateUsage') +); + +/** + * 校验规则: + * 1. 确保成员属性或方法不能同时被多个内置装饰器(`@Local`, `@Param`, `@Event`)装饰; + * 2. 当用`@Param`装饰的变量没有被分配默认值时,它也必须用`@Require`装饰; + * 3. 在被`@ComponentV2`装饰的结构体中,`@Require`只能与`@Param`一起使用; + * 4. 检查`@ComponentV2`自定义组件中的`@Local`属性和无装饰器属性是否尝试在外部初始化; + * 5. 确保`@Local`,`@Param`,`@Event`装饰器只能用于成员属性,而不能用于方法。 + * + * 校验等级:error + */ +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 _node = coerceToAstNode(node); + 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 (!_node.value && 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, `Add @Require annotation`), + }); + } + // 在被`@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), + `Remove the @Require annotation` + ), + }); + } +} + +function checkComponentV2StateUsageInStructCall( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structDeclInfo?.name) { + return; + } + const hasComponentV2: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasComponentV2; + if (!hasComponentV2) { + return; + } + const structName = metadata.structDeclInfo.name; + const propertyInfos = metadata.structPropertyInfos ?? []; + // 检查自定义组件中的`@Local`属性和无装饰器属性是否尝试在外部初始化 + for (const propInfo of propertyInfos) { + const propPtr = propInfo[0]; + const propertyInfo = propInfo[1]; + 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 && !!propertyInfo?.name) { + const prop = arkts.unpackNode(propPtr)!; + this.report({ + node: prop, + message: getLocalNeedNoInitReportMessage(reportDecoratorName, propertyInfo?.name, structName), + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(prop), `Remove the property`), + }); + } + } +} + +function checkComponentV2StateUsageInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const decorators = findInvalidBuiltInDecoratorUsage(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), `Remove the annotation`), + }) + ); + } +} + +function checkComponentV2StateUsageInClass( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const decorators = findInvalidBuiltInDecoratorUsage(metadata); + 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), `Remove the 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, checkComponentV2StateUsageInMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, checkComponentV2StateUsageInClass], +]); + +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 findInvalidBuiltInDecoratorUsage(info: StructMethodInfo | FunctionInfo): DecoratorInfo[] { + if (!info.ignoredAnnotationInfo || !info.ignoredAnnotations) { + return []; + } + return builtInDecorators + .filter((name) => !!info.ignoredAnnotationInfo?.[`has${name}`]) + .map((name) => ({ + name, + annotation: info.ignoredAnnotations?.[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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..84a19a4818d5a49d56bee0f5da19cea8d9010cc9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-computed-decorator.ts @@ -0,0 +1,279 @@ +/* + * 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, + getPositionRangeFromAnnotation, + getPositionRangeFromNode, +} from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkComputedDecorator = performanceLog( + _checkComputedDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkComputedDecorator') +); + +/** + * 校验规则: + * 1. `@Computed`装饰器只能用来装饰获取器(即`getter`方法); + * 2. `@Computed`装饰器在已经被`@ObservedV2`装饰器装饰的类`class`中的成员方法上使用; + * 3. `@Computed`装饰器在已经被`@ComponentV2`装饰器修饰的结构体`struct`中使用 + * 4. `@Computed`装饰器修饰的属性不能与双向绑定语法一起使用; + * 5. `@Computed`装饰器修饰的属性不能定义一个设置器(即`setter`方法)。 + * + * 校验等级:error + */ +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), `Remove the set method`), + }); + } + 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( + '', + ...getPositionRangeFromAnnotation(computedAnnotation), + `Remove the annotation` + ), + }); + } else if (!checkIsFromObervedV2InNormalClass(metadata) && !!classDef?.parent) { + const observed = metadata.classInfo?.annotations?.[DecoratorNames.OBSERVED]; + const suggestion = observed + ? createSuggestion( + `${DecoratorNames.OBSERVED_V2}`, + ...getPositionRangeFromNode(observed), + `Change @Observed to @ObservedV2` + ) + : createSuggestion( + `@${DecoratorNames.OBSERVED_V2}\n`, + classDef.parent.startPosition, + classDef.parent.startPosition, + `Add @ObservedV2 decorator` + ); + // `@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: suggestion, + }); + } else if ( + !checkIsFromComponentV2InStruct(metadata) && + !!classDef?.parent && + metadata.structInfo?.annotationInfo?.hasComponent + ) { + const componentAnnotation = metadata.structInfo?.annotations?.[StructDecoratorNames.COMPONENT]!; + // `@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(componentAnnotation), + `Change @Component to @ComponentV2` + ), + }); + } +} + +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( + '', + ...getPositionRangeFromAnnotation(computedAnnotation), + `Remove the annotation` + ), + }); +} + +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, + }); + }); + }); +} + +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: 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.id!.name; + return classDecl.body.find( + (st) => arkts.isMethodDefinition(st) && checkIsGetterMethod(st) && st.id!.name === name + ) as arkts.MethodDefinition | undefined; +} + +function checkIsMethodHasComputed(node: arkts.MethodDefinition): boolean { + const annotationRecord = new NormalClassMethodAnnotationRecord({ shouldIgnoreDecl: false }); + for (const annotation of node.function.annotations) { + annotationRecord.collect(annotation); + } + const annotationInfo = annotationRecord.toRecord(); + return !!annotationInfo?.annotationInfo?.hasComputed; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter-literal.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd0af61855be8c6ff203f88d986c56f0cc16f8c9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter-literal.ts @@ -0,0 +1,104 @@ +/* + * 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 { CallInfo, RecordBuilder, StructPropertyRecord } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkConstructParameterLiteral = performanceLog( + _checkConstructParameterLiteral, + getPerfName([0, 0, 0, 0, 0], 'checkConstructParameterLiteral') +); + +/** + * 校验规则:用于验证自定义组件初始化属性时使用的装饰器类型。 + * 1.`@ObjectLink`与`@Link`修饰的变量,禁止使用常量初始化。 + * + * 校验等级:error + */ +function _checkConstructParameterLiteral( + this: BaseValidator, + node: arkts.CallExpression +): void { + const metadata = this.context ?? {}; + // If a non-custom component is called and is not in the custom component, it returns directly + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + metadata.structPropertyInfos?.forEach(([propertyPtr, propertyInfo]) => { + if (!propertyPtr || !propertyInfo) { + return; + } + if (!propertyInfo.annotationInfo?.hasLink && !propertyInfo.annotationInfo?.hasObjectLink) { + return; + } + const annotationName = propertyInfo.annotationInfo?.hasLink ? DecoratorNames.LINK : DecoratorNames.OBJECT_LINK; + const property = arkts.unpackNonNullableNode(propertyPtr); + + const errorNode = verifyRegularInitialization(property); + if (!errorNode) { + return; + } + // `@ObjectLink`与`@Link`修饰的变量,禁止使用常量初始化。 + this.report({ + node: property, + level: LogType.WARN, + message: `The 'regular' property '${errorNode.dumpSrc()}' cannot be assigned to the '@${annotationName}' property '${propertyInfo.name}'.`, + }); + }); +} + +function verifyRegularInitialization(property: arkts.Property): arkts.AstNode | undefined { + const key = property.key; + const value = property.value; + if (!key || !arkts.isIdentifier(key) || !value) { + return undefined; + } + // Skip checks when assigning this.xxx attributes and global variables + if (arkts.isMemberExpression(value)) { + return verifyRegularInitializationInMemberExpression(value); + } + if (!arkts.isMethodDefinition(value) && !arkts.isIdentifier(value)) { + return value; + } + return undefined; +} + +function verifyRegularInitializationInMemberExpression(member: arkts.MemberExpression): arkts.AstNode | undefined { + const object = member.object; + if (arkts.isThisExpression(object)) { + return undefined; + } + const property = member.property; + if (!arkts.isIdentifier(property)) { + return undefined; + } + const decl = arkts.getPeerIdentifierDecl(property.peer); + if (!decl || !arkts.isClassProperty(decl)) { + return undefined; + } + const structPropertyRecord = RecordBuilder.build(StructPropertyRecord, decl, { shouldIgnoreDecl: false }); + if (!structPropertyRecord.isCollected) { + structPropertyRecord.collect(decl); + } + const structPropertyInfo = structPropertyRecord.toRecord(); + const info = { ...structPropertyInfo?.annotationInfo, ...structPropertyInfo?.ignoredAnnotationInfo }; + if (Object.keys(info).length > 0) { + return undefined; + } + return property; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef8695d623104c5efb76bc3a9653bc869a643226 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-parameter.ts @@ -0,0 +1,191 @@ +/* + * 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 { CallInfo } from '../../records'; +import { isVariableDeclaration, isFunctionDeclaration } from '../utils'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkConstructParameter = performanceLog( + _checkConstructParameter, + getPerfName([0, 0, 0, 0, 0], 'checkConstructParameter') +); + +// The decorator structure prohibits initializing the assignment list +const restrictedDecoratorInitializations: Map = new Map([ + [DecoratorNames.REGULAR, [DecoratorNames.OBJECT_LINK, DecoratorNames.LINK]], + [DecoratorNames.PROVIDE, [DecoratorNames.REGULAR]], + [DecoratorNames.CONSUME, [DecoratorNames.REGULAR]], + [DecoratorNames.STORAGE_PROP_REF, [DecoratorNames.REGULAR]], + [DecoratorNames.VARIABLE, [DecoratorNames.LINK]], + [DecoratorNames.LOCAL_STORAGE_LINK, [DecoratorNames.REGULAR]], +]); + +/** + * 校验规则:用于验证自定义组件初始化属性时使用的装饰器类型。 + * 1. 特定装饰器修饰属性在组件构造初始化赋值时报错 + * 2. 当`@Builder`函数被用于初始化非`@BuilderParam`属性时报错 + * 3. 当`@BuilderParam`属性被非`@Builder`函数或方法初始化时报错 + * + * 校验等级:error + */ +function _checkConstructParameter( + this: BaseValidator, + node: arkts.CallExpression +): void { + const metadata = this.context ?? {}; + // If a non-custom component is called and is not in the custom component, it returns directly + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + metadata.structPropertyInfos?.forEach(([propertyPtr, propertyInfo]) => { + if (!propertyPtr || !propertyInfo) { + return; + } + const property = arkts.unpackNonNullableNode(propertyPtr); + const initializerProperty = property.key; + const parameterProperty = property.value; + + // Subsequent validation is performed only if the parameterProperty is in this.xxx format or identifier + if (!initializerProperty || !parameterProperty || !arkts.isIdentifier(initializerProperty)) { + return; + } + const initializerName = initializerProperty.name; + if (initializerName === '') { + return; + } + const initializerAnnotations: string[] = []; + for (const annotationKey in propertyInfo.annotations) { + initializerAnnotations.push(annotationKey); + } + for (const annotationKey in propertyInfo.ignoredAnnotations) { + initializerAnnotations.push(annotationKey); + } + if (initializerAnnotations.length === 0) { + initializerAnnotations.push(DecoratorNames.REGULAR); + } + + const { parameterAnnotations, parameterName } = getParameterAnnotationsAndName(parameterProperty); + if (parameterAnnotations.length === 0 || parameterName === '') { + return; + } + checkAndReportError.bind(this)( + initializerAnnotations, + parameterAnnotations, + initializerName, + parameterName, + property + ); + }); +} + +export function checkAndReportError( + this: BaseValidator, + initializerAnnotations: string[], + parameterAnnotations: string[], + initializerName: string, + parameterName: string, + property: arkts.Property +): void { + // 特定装饰器修饰属性在组件构造初始化赋值时报错 + parameterAnnotations.forEach((annotationName) => { + if (!restrictedDecoratorInitializations.has(annotationName)) { + return; + } + const cannotInitialize = restrictedDecoratorInitializations.get(annotationName)!; + cannotInitialize.forEach((cannotInitializeAnnotationName) => { + if (!initializerAnnotations.includes(cannotInitializeAnnotationName)) { + return; + } + this.report({ + node: property, + level: LogType.ERROR, + message: `The '${annotationName}' property '${initializerName}' cannot be assigned to the '${cannotInitializeAnnotationName}' property '${parameterName}'.`, + }); + }); + }); + // 当`@Builder`函数被用于初始化非`@BuilderParam`属性时报错 + if ( + parameterAnnotations.includes(DecoratorNames.BUILDER) && + !initializerAnnotations.includes(DecoratorNames.BUILDER_PARAM) + ) { + this.report({ + node: property, + level: LogType.ERROR, + message: `'@Builder' function '${initializerName}' can only initialize '@BuilderParam' attribute.`, + }); + } + // 当`@BuilderParam`属性被非`@Builder`函数或方法初始化时报错 + if ( + !parameterAnnotations.includes(DecoratorNames.BUILDER) && + initializerAnnotations.includes(DecoratorNames.BUILDER_PARAM) + ) { + this.report({ + node: property, + level: LogType.WARN, + message: `'@BuilderParam' attribute '${parameterName}' can only initialized by '@Builder' function or '@Builder' method in struct.`, + }); + } +} + +function getParameterAnnotationsAndName(parameterProperty: arkts.AstNode): { + parameterAnnotations: string[]; + parameterName: string; +} { + const isIdentifierParameter = arkts.isIdentifier(parameterProperty); + const isThisParameter = + arkts.isMemberExpression(parameterProperty) && arkts.isThisExpression(parameterProperty.object); + let parameterAnnotations: string[] = []; + let parameterName: string = ''; + if (isIdentifierParameter) { + parameterName = parameterProperty.name; + const parameterNode = arkts.getPeerIdentifierDecl(parameterProperty.peer); + if (parameterNode && isVariableDeclaration(parameterNode)) { + return { parameterAnnotations: [DecoratorNames.VARIABLE], parameterName: parameterName }; + } + if (!parameterNode || !isFunctionDeclaration(parameterNode)) { + return { parameterAnnotations: [], parameterName: '' }; + } + const funcAnnotations = parameterNode.function.annotations; + if (!funcAnnotations || funcAnnotations.length === 0) { + return { parameterAnnotations: [DecoratorNames.REGULAR], parameterName: parameterName }; + } + funcAnnotations.forEach((annotation) => { + if (!annotation.expr || !arkts.isIdentifier(annotation.expr) || annotation.expr.name === '') { + return; + } + parameterAnnotations.push(annotation.expr.name); + }); + } + if (isThisParameter) { + const propertyDecl = arkts.getPeerIdentifierDecl(parameterProperty.property!.peer); + if (!propertyDecl || !arkts.isClassProperty(propertyDecl) || !arkts.isIdentifier(parameterProperty.property)) { + return { parameterAnnotations: [], parameterName: '' }; + } + parameterName = parameterProperty.property.name; + if (propertyDecl.annotations.length === 0) { + return { parameterAnnotations: [DecoratorNames.REGULAR], parameterName: parameterName }; + } + propertyDecl.annotations.forEach((annotation) => { + if (!annotation.expr || !arkts.isIdentifier(annotation.expr) || annotation.expr.name === '') { + return; + } + parameterAnnotations.push(annotation.expr.name); + }); + } + return { parameterAnnotations, parameterName }; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-private-parameter.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-private-parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..800887d1198d098d0bf5cb119c97a3384540001d --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-construct-private-parameter.ts @@ -0,0 +1,72 @@ +/* + * 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 { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { isPrivateClassProperty } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkConstructPrivateParameter = performanceLog( + _checkConstructPrivateParameter, + getPerfName([0, 0, 0, 0, 0], 'checkConstructPrivateParameter') +); + +/** + * 校验规则:用于校验通过组件构造函数初始化变量是否为私有访问权限。 + * + * 校验等级:warn + */ +function _checkConstructPrivateParameter( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + // If a non-custom component is called and is not in the custom component, it returns directly + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + if (!struct || !struct.parent || !arkts.isClassDeclaration(struct.parent)) { + return; + } + let privateClassProperty: string[] = []; + struct.parent?.definition?.body.forEach((property) => { + if (!arkts.isClassProperty(property) || !property.key || !arkts.isIdentifier(property.key)) { + return; + } + + const propertyName = property.key.name; + if (propertyName === '') { + return; + } + if (!isPrivateClassProperty(property)) { + return; + } + privateClassProperty.push(propertyName); + }); + metadata.structPropertyInfos?.forEach(([propertyPtr, propertyInfo]) => { + // 用于校验通过组件构造函数初始化变量是否为私有访问权限 + if (!propertyPtr || !propertyInfo || !propertyInfo.name || !privateClassProperty.includes(propertyInfo.name)) { + return; + } + const property = arkts.unpackNonNullableNode(propertyPtr); + this.report({ + node: property, + level: LogType.WARN, + message: `Property '${propertyInfo?.name}' is private and can not be initialized through the component constructor.`, + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..3143fdc0ade103aaa2702ef22b68f8ec2bb68000 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-consumer-provider-decorator.ts @@ -0,0 +1,257 @@ +/* + * 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, + CustomComponentInterfacePropertyInfo, + CustomComponentInterfacePropertyRecord, + NormalClassPropertyInfo, + RecordBuilder, + StructMethodInfo, + StructPropertyInfo, + NormalClassInfo, +} from '../../records'; +import { checkIsNameStartWithBackingField } from '../../utils'; +import { DecoratorNames, LogType, StateManagementTypes } from '../../../../common/predefines'; +import { + createSuggestion, + getPositionRangeFromAnnotation, + getPositionRangeFromNode, +} from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkConsumerProviderDecorator = performanceLog( + _checkConsumerProviderDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkConsumerProviderDecorator') +); + +/** + * 校验规则: + * 1. `@Provider`/`@Consumer`只能用来修饰类成员属性(不能修饰方法、参数等); + * 2. 结构体成员变量不能被多个内置装饰器修饰; + * 3. `@Provider`/`@Consumer`装饰器只能用于`struct`类型,而不能用于类(`class`)或其他类型; + * 4. 自定义组件中的`@Provider`/`@Consumer`装饰的属性不能在父组件初始化(禁止指定初始值)。 + * + * 校验等级:error + */ +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('', ...getPositionRangeFromAnnotation(annotation), `Remove the 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('', ...getPositionRangeFromAnnotation(annotation), `Remove the 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('', ...getPositionRangeFromAnnotation(annotation), `Remove the 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('', ...getPositionRangeFromAnnotation(annotation), `Remove the annotation`), + }); + } + // 结构体成员变量不能被多个内置装饰器修饰; + let foundOther: arkts.AnnotationUsage | undefined; + if ( + metadata.annotationInfo?.hasConsumer && + !!(foundOther = findOtherDecoratorFromInfo(metadata, DecoratorNames.CONSUMER)) + ) { + const annotation = metadata.annotations?.[DecoratorNames.CONSUMER]!; + this.report({ + node: annotation, + message: `The struct member variable can not be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromAnnotation(annotation), `Remove other annotations`), + }); + } + if ( + metadata.annotationInfo?.hasProvider && + !!(foundOther = findOtherDecoratorFromInfo(metadata, DecoratorNames.PROVIDER)) + ) { + const annotation = metadata.annotations?.[DecoratorNames.PROVIDER]!; + this.report({ + node: annotation, + message: `The struct member variable can not be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromAnnotation(annotation), `Remove other annotations`), + }); + } +} + +function checkConsumerProviderDecoratorInStructCall( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.structDeclInfo?.name) { + return; + } + const structName = metadata.structDeclInfo.name; + const propertyInfos = metadata.structPropertyInfos ?? []; + // 自定义组件中的`@Provider`/`@Consumer`装饰的属性不能在父组件初始化(禁止指定初始值) + for (const propInfo of propertyInfos) { + const propPtr = propInfo[0]; + const propertyInfo = propInfo[1]; + if (!propertyInfo?.name || propertyInfo.name.startsWith(StateManagementTypes.BACKING)) { + return; + } + const decoratorInfo = findConsumerOrProviderFromInterfacePropertyInfo(propertyInfo); + if (!!decoratorInfo) { + const prop = arkts.unpackNode(propPtr)!; + this.report({ + node: prop, + message: getForbiddenInitializationMessage(decoratorInfo.name, propertyInfo.name, structName), + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromNode(node), `Remove the property`), + }); + } + } +} + +function checkConsumerProviderDecoratorInNormalClass( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + //`@Provider`/`@Consumer`装饰器只能用于`struct`类型,而不能用于类(`class`)或其他类型; + if (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('', ...getPositionRangeFromAnnotation(annotation), `Remove the annotation`), + }); + } + if (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('', ...getPositionRangeFromAnnotation(annotation), `Remove the annotation`), + }); + } +} + +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], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, checkConsumerProviderDecoratorInNormalClass], +]); + +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 findConsumerOrProviderFromInterfacePropertyInfo( + propertyInfo: CustomComponentInterfacePropertyInfo +): DecoratorInfo | undefined { + 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 findConsumerOrProviderFromInterfaceProperty(property: arkts.MethodDefinition): DecoratorInfo | undefined { + const structInterfacePropRecord = RecordBuilder.build(CustomComponentInterfacePropertyRecord, property, { + shouldIgnoreDecl: 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/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-custom-dialog-missing-controller.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-custom-dialog-missing-controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..90b320dca1645c1b59da45ae8fb8a45d7b59c45c --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-custom-dialog-missing-controller.ts @@ -0,0 +1,101 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkCustomDialogMissingController = performanceLog( + _checkCustomDialogMissingController, + getPerfName([0, 0, 0, 0, 0], 'checkCustomDialogMissingController') +); + +const CUSTOM_DIALOG_CONTROLLER = 'CustomDialogController'; +const UNION_TYPE_NUM_LIMIT = 2; + +/** + * 校验规则:用于验证`@CustomDialog` 装饰器约束条件 + * 1. 使用 `@CustomDialog` 装饰器装饰的自定义组件必须包含一个类型为 `CustomDialogController` 的属性。 + * + * 校验等级:error + */ +function _checkCustomDialogMissingController( + this: BaseValidator, + struct: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const hasCustomDialog = !!metadata.annotationInfo?.hasCustomDialog; + const hasCustomDialogControllerProperty = struct.definition?.body.some((property) => { + // The joint type also report error, such as CustomDialogController | undefined + if (arkts.isClassProperty(property)) { + return checkPropertyIsCustomDialogController(property); + } + }); + + // 使用 `@CustomDialog` 装饰器装饰的自定义组件必须包含一个类型为 `CustomDialogController` 的属性。 + if (hasCustomDialog && !hasCustomDialogControllerProperty) { + if (!struct.definition || !struct.definition.ident) { + return; + } + this.report({ + node: struct.definition.ident, + level: LogType.ERROR, + message: `The @CustomDialog decorated custom component must contain a property of the CustomDialogController type.`, + }); + } +} + +function checkPropertyIsCustomDialogController(property: arkts.ClassProperty): boolean { + const typeAnnotation = property.typeAnnotation; + if (!typeAnnotation) { + return false; + } + if (arkts.isETSTypeReference(typeAnnotation)) { + return checkETSTypeReference(typeAnnotation); + } + if (arkts.isETSUnionType(typeAnnotation)) { + return checkETSUnionType(typeAnnotation); + } + return false; +} + +function checkETSTypeReference(type: arkts.ETSTypeReference): boolean { + return !!( + type.part && + type.part.name && + arkts.isIdentifier(type.part.name) && + type.part.name.name === CUSTOM_DIALOG_CONTROLLER + ); +} + +function checkETSUnionType(type: arkts.ETSUnionType): boolean { + if (type.types.length !== UNION_TYPE_NUM_LIMIT) { + return false; + } + + let hasCustomDialog: boolean = false; + let hasUndefined: boolean = false; + for (const nodeType of type.types) { + if (arkts.isETSTypeReference(nodeType) && checkETSTypeReference(nodeType)) { + hasCustomDialog = true; + } + if (arkts.isETSUndefinedType(nodeType)) { + hasUndefined = true; + } + } + return hasCustomDialog && hasUndefined; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-decorated-property-type.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-decorated-property-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..94c251eaf79a5f8013248d12af8a605d86b28512 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-decorated-property-type.ts @@ -0,0 +1,134 @@ +/* + * 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 { isDeclFromArkUI } from '../../utils'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { expectNameInTypeReference } from '../../../../common/arkts-utils'; + +export const checkDecoratedPropertyType = performanceLog( + _checkDecoratedPropertyType, + getPerfName([0, 0, 0, 0, 0], 'checkDecoratedPropertyType') +); + +const forbiddenUseStateTypeForDecorators: string[] = [ + DecoratorNames.STATE, + DecoratorNames.PROP_REF, + DecoratorNames.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.OBJECT_LINK, + DecoratorNames.BUILDER_PARAM, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.STORAGE_LINK, + DecoratorNames.LOCAL_STORAGE_LINK, +]; + +const forbiddenUseStateType: string[] = [ + 'Scroller', + 'SwiperScroller', + 'VideoController', + 'WebController', + 'CustomDialogController', + 'SwiperController', + 'TabsController', + 'CalendarController', + 'AbilityController', + 'XComponentController', + 'CanvasRenderingContext2D', + 'CanvasGradient', + 'ImageBitmap', + 'ImageData', + 'Path2D', + 'RenderingContextSettings', + 'OffscreenCanvasRenderingContext2D', + 'PatternLockController', + 'TextAreaController', + 'TextInputController', + 'TextTimerController', + 'SearchController', + 'RichEditorController', +]; + +/** + * 校验规则:用于检查装饰器与属性类型的组合是否有效 + * 1. forbiddenUseStateTypeForDecorators中的装饰器不允许与forbiddenUseStateType中的属性类型组合使用 + * + * 校验等级:error + */ +function _checkDecoratedPropertyType( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo) { + return; + } + const forbiddenUseAnnotation = forbiddenUseStateTypeForDecorators.find((annotationName) => { + return !!metadata.annotations?.[annotationName]; + }); + if (!forbiddenUseAnnotation) { + return; + } + const forbiddenUseType = findForbiddenDeclNameFromType(classProperty.typeAnnotation); + if (!forbiddenUseType) { + return; + } + // forbiddenUseStateTypeForDecorators中的装饰器不允许与forbiddenUseStateType中的属性类型组合使用 + this.report({ + node: classProperty, + level: LogType.ERROR, + message: `The '@${forbiddenUseAnnotation}' property '${metadata.name}' cannot be a '${forbiddenUseType}' object.`, + }); +} + +function findForbiddenDeclNameFromType(node: arkts.TypeNode | undefined): string | undefined { + if (!node) { + return undefined; + } + if (arkts.isETSUnionType(node)) { + for (const type of node.types) { + const targetName = findForbiddenDeclNameFromType(type); + if (!targetName) { + return targetName; + } + } + return undefined; + } + if (arkts.isETSTypeReference(node)) { + const nameNode = expectNameInTypeReference(node); + if (!nameNode) { + return undefined; + } + const decl = arkts.getPeerIdentifierDecl(nameNode.peer); + if (!decl || !isDeclFromArkUI(decl)) { + return undefined; + } + let name: string | undefined; + if (arkts.isClassDefinition(decl)) { + name = decl.ident?.name; + } else if (arkts.isTSInterfaceDeclaration(decl)) { + name = decl.id?.name; + } + if (!name) { + return undefined; + } + return forbiddenUseStateType.find((n) => n === name); + } + return undefined; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.ts new file mode 100644 index 0000000000000000000000000000000000000000..439424a39aa458888c702bc334ec0c62e69c8b9e --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-localstorage.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 { StructPropertyInfo } from '../../records'; +import { EntryParamNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkEntryLocalStorage = performanceLog( + _checkEntryLocalStorage, + getPerfName([0, 0, 0, 0, 0], 'checkEntryLocalStorage') +); + +/** + * 校验规则:`struct`结构体中使用了`@LocalStorageLink`来绑定属性,需要在`@Entry`装饰器中传入storage参数 + * + * 校验等级:warn + */ +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]!; + // `struct`结构体中使用了`@LocalStorageLink`来绑定属性,需要在`@Entry`装饰器中传入storage参数 + 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.some((prop) => { + return ( + arkts.isClassProperty(prop) && + prop.key && + arkts.isIdentifier(prop.key) && + prop.key.name === EntryParamNames.ENTRY_STORAGE && + prop.value && + arkts.isStringLiteral(prop.value) && + prop.value.str.length > 0 + ); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-struct-no-export.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-struct-no-export.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab7713edd587996cf54ba569dc990294413398a9 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-entry-struct-no-export.ts @@ -0,0 +1,46 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkEntryStructNoExport = performanceLog( + _checkEntryStructNoExport, + getPerfName([0, 0, 0, 0, 0], 'checkEntryStructNoExport') +); + +function _checkEntryStructNoExport( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const entryDecoratorUsage = metadata.annotations?.Entry; + if (!entryDecoratorUsage) { + return; + } + + const isExport = node.isExport; + const isDefaultExport = node.isDefaultExport; + if (isExport || isDefaultExport) { + this.report({ + node: entryDecoratorUsage, + level: LogType.WARN, + message: `It's not a recommended way to export struct with '@Entry' annotation, which may cause ACE Engine error in component preview mode.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-main-pages-entry-check.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-main-pages-entry-check.ts new file mode 100644 index 0000000000000000000000000000000000000000..1deb4bd32a90bd19f00cc69b46a5a1562d0a0ec2 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-main-pages-entry-check.ts @@ -0,0 +1,72 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { getCurrentFilePath } from '../utils'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { MetaDataCollector } from '../../../../common/metadata-collector'; + +export const checkMainPagesEntry = performanceLog( + _checkMainPagesEntry, + getPerfName([0, 0, 0, 0, 0], 'checkMainPagesEntry') +); + +export function resetMainPagesEntry(this: BaseValidator): void { + Array.from(declaredStructMap.values()).forEach((structInfo) => { + if (!structInfo.hasEntry) { + this.report({ + node: structInfo.firstStruct, + level: LogType.ERROR, + message: `A page configured in 'main_pages.json or build-profile.json5' must have one and only one '@Entry' annotation.`, + }); + } + }); + declaredStructMap.clear(); +} + +interface MainPageStructInfo { + hasEntry?: boolean; + firstStruct: arkts.ClassDeclaration; +} + +const declaredStructMap: Map = new Map(); + +/** + * 校验规则:在`main pages`中配置的页面,必须有且只有一个`@Entry`装饰器。 + * + * 校验等级:error + */ +function _checkMainPagesEntry( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const currentFilePath = getCurrentFilePath(node); + const mainPages = MetaDataCollector.getInstance().mainPageNames; + if (!currentFilePath || !mainPages || !mainPages.includes(currentFilePath)) { + return; + } + const structInfo = declaredStructMap.get(currentFilePath); + if (!!structInfo && !!structInfo.hasEntry) { + return; + } + declaredStructMap.set(currentFilePath, { + hasEntry: metadata.annotationInfo?.hasEntry, + firstStruct: structInfo?.firstStruct ?? node, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-monitor-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-monitor-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..e064628649eb1a4365be3cb6bc31565e577ffc92 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-monitor-decorator.ts @@ -0,0 +1,196 @@ +/* + * 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 type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { NormalClassMethodInfo, NormalClassPropertyInfo, StructMethodInfo, StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; +import { + createSuggestion, + getPositionRangeFromAnnotation, + getPositionRangeFromNode, +} from '../../../../common/log-collector'; +import { + checkIsNormalClassMethodFromInfo, + checkIsStructMethodFromInfo, +} from '../../../../collectors/ui-collectors/utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkMonitorDecorator = performanceLog( + _checkMonitorDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkMonitorDecorator') +); + +/** + * 校验规则:用于验证`@Monitor` 装饰器约束条件 + * 1. `@Monitor`不能与其他内置装饰器一起使用 + * 2. `@Monitor`装饰器只能用于被`@ObservedV2`装饰的类中的成员方法上 + * 3. `@Monitor`装饰器只能在被`@ComponentV2`装饰的`struct`中使用 + * 4. `@Monitor`装饰器只能用来装饰方法 + * + * 校验等级:error + */ +function _checkMonitorDecorator(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkMonitorDecoratorInMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkMonitorDecoratorInClassProperty], +]); + +function checkMonitorDecoratorInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const monitorUsage = metadata.annotations?.Monitor; + if (!monitorUsage) { + return; + } + + if (checkIsStructMethodFromInfo(metadata)) { + checkMonitorInComponentV2Struct.bind(this)(monitorUsage); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkMonitorInObservedV2Class.bind(this)(monitorUsage); + } + + const annotationNumOfMethod = countAnnotationOfMethod(metadata); + const otherAnnotation: arkts.AnnotationUsage | undefined = findOtherAnnotation(metadata); + if (annotationNumOfMethod <= 1 || !otherAnnotation) { + return; + } + + this.report({ + node: monitorUsage, + message: `The member property or method cannot be decorated by multiple built-in annotations.`, + level: LogType.ERROR, + suggestion: createSuggestion(``, ...getPositionRangeFromAnnotation(otherAnnotation), `Remove the annotation`), + }); +} + +function checkMonitorInComponentV2Struct( + this: BaseValidator, + monitorUsage: arkts.AnnotationUsage +): void { + const metadata = this.context ?? {}; + if (metadata.structInfo?.annotationInfo?.hasComponentV2) { + return; + } + + const componentUsage = metadata.structInfo?.annotations?.Component; + if (componentUsage) { + this.report({ + node: monitorUsage, + message: `The '@Monitor' annotation can only be used in a 'struct' decorated with '@ComponentV2'.`, + level: LogType.ERROR, + suggestion: createSuggestion( + `${StructDecoratorNames.COMPONENT_V2}`, + ...getPositionRangeFromNode(componentUsage), + `Change @Component to @ComponentV2` + ), + }); + } +} + +function checkMonitorInObservedV2Class( + this: BaseValidator, + monitorUsage: arkts.AnnotationUsage +): void { + const metadata = this.context ?? {}; + if (metadata.classInfo?.annotationInfo?.hasObservedV2) { + return; + } + + const observedUsage = metadata.classInfo?.annotations?.Observed; + if (observedUsage) { + this.report({ + node: monitorUsage, + message: `The '@Monitor' can decorate only member 'method' within a 'class' decorated with '@ObservedV2'.`, + level: LogType.ERROR, + suggestion: createSuggestion( + `${DecoratorNames.OBSERVED_V2}`, + ...getPositionRangeFromNode(observedUsage), + `Change @Observed to @ObservedV2` + ), + }); + } else { + const classDeclaration = arkts.unpackNonNullableNode(metadata.classInfo?.definitionPtr!); + this.report({ + node: monitorUsage, + level: LogType.ERROR, + message: `The '@Monitor' can decorate only member method within a 'class' decorated with @ObservedV2.`, + suggestion: createSuggestion( + `@${DecoratorNames.OBSERVED_V2}\n`, + classDeclaration.startPosition, + classDeclaration.startPosition, + `Add @ObservedV2 annotation` + ), + }); + } +} + +function checkMonitorDecoratorInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const monitorUsage = metadata.ignoredAnnotations?.Monitor; + if (!monitorUsage) { + return; + } + + this.report({ + node: monitorUsage, + message: `@Monitor can only decorate method.`, + level: LogType.ERROR, + suggestion: createSuggestion( + ``, + ...getPositionRangeFromAnnotation(monitorUsage), + `Remove the @Monitor annotation` + ), + }); +} + +function countAnnotationOfMethod(metadata: NormalClassMethodInfo | StructMethodInfo): number { + let count = 0; + Object.values(DecoratorNames).forEach((key) => { + if (metadata.annotationInfo?.[`has${key}`] || metadata.ignoredAnnotationInfo?.[`has${key}`]) { + count++; + } + }); + return count; +} + +function findOtherAnnotation(metadata: NormalClassMethodInfo | StructMethodInfo): arkts.AnnotationUsage | undefined { + let otherAnnotation: arkts.AnnotationUsage | undefined = undefined; + for (const key of Object.values(DecoratorNames)) { + if (otherAnnotation) { + break; + } + if (metadata.annotations?.[key]) { + otherAnnotation = metadata.annotations?.[key]; + } + if (metadata.ignoredAnnotations?.[key]) { + otherAnnotation = metadata.ignoredAnnotations?.[key]; + } + } + return otherAnnotation; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e3ef253bf5c7126aadba3ddbcd9a775cdc4c891 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-relationship.ts @@ -0,0 +1,298 @@ +/* + * 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 { isBuiltInDeclaration } from '../utils'; +import { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { MetaDataCollector } from '../../../../common/metadata-collector'; + +export const checkNestedRelationship = performanceLog( + _checkNestedRelationship, + getPerfName([0, 0, 0, 0, 0], 'checkNestedRelationship') +); + +const SINGLE_CHILD_COMPONENT = 1; + +const renderingConrtrolComponents: Set = new Set(['ForEach', 'LazyForEach', 'Repeat']); + +/** + * 校验规则: + * 1. 原子组件不可包含子组件; + * 2. 单子组件最多允许包含一个组件; + * 3. 特定组件的父组件必须是限定组件; + * 4. 特定组件的子组件必须是限定组件。 + * + * 校验等级:error + */ +function _checkNestedRelationship( + this: BaseValidator, + node: arkts.CallExpression +): void { + const metadata = this.context ?? {}; + if (!metadata.annotationInfo?.hasComponentBuilder || !!metadata.structDeclInfo) { + return; + } + const componentsInfo = MetaDataCollector.getInstance().componentsInfo; + if (!componentsInfo || !metadata.declName || !arkts.isIdentifier(node.callee)) { + return; + } + + // Check if there are any restrictions on the node parent component + if (componentsInfo.validParentComponent.has(metadata.declName)) { + const parentComponentNames = componentsInfo.validParentComponent.get(metadata.declName)!; + checkValidParentComponent.bind(this)(node.callee, metadata.declName, parentComponentNames); + } + // Check if the node's sub components have limitations + if (componentsInfo.validChildComponent.has(metadata.declName)) { + const childComponentNames = componentsInfo.validChildComponent.get(metadata.declName)!; + checkValidChildComponent.bind(this)(node.callee, metadata.declName, childComponentNames); + } + // Check whether the current node is a single subComponent container + if (componentsInfo.singleChildComponents.includes(metadata.declName)) { + checkSingleChildComponent.bind(this)(node.callee, metadata.declName); + } + // Check whether the current node is an atomic component + if (componentsInfo.atomicComponents.includes(metadata.declName)) { + checkNoChildComponent.bind(this)(node.callee, metadata.declName); + } +} + +function checkValidParentComponent( + this: BaseValidator, + componentIdentifier: arkts.Identifier, + componentName: string, + parentComponentNames: string[] +): void { + if (!componentIdentifier.parent || !componentIdentifier.parent.parent) { + return; + } + let curNode = componentIdentifier.parent.parent; + let foundRenderingComponent: boolean = false; + while ( + !arkts.isCallExpression(curNode) || + !arkts.isIdentifier(curNode.callee) || + !isBuiltInComponent.bind(this)(curNode.callee) + ) { + if (!curNode.parent) { + return; + } + if ( + arkts.isCallExpression(curNode) && + arkts.isIdentifier(curNode.callee) && + renderingConrtrolComponents.has(curNode.callee.name) + ) { + foundRenderingComponent = true; + } + curNode = curNode.parent; + } + // If the parent component of the current component is not within the valid range, an error is reported + const parentComponentName = curNode.callee.name; + if (parentComponentNames.includes(parentComponentName)) { + return; + } + + if (foundRenderingComponent) { + this.report({ + node: componentIdentifier, + level: LogType.WARN, + message: `The '${componentName}' component can only be nested in the '${listToString( + parentComponentNames + )}' parent component.`, + }); + } else { + this.report({ + node: componentIdentifier, + level: LogType.ERROR, + message: `The '${componentName}' component can only be nested in the '${listToString( + parentComponentNames + )}' parent component.`, + }); + } +} + +function checkValidChildComponent( + this: BaseValidator, + componentIdentifier: arkts.Identifier, + componentName: string, + childComponentNames: string[] +): void { + if (!componentIdentifier.parent || !componentIdentifier.parent.parent) { + return; + } + let parentNode = componentIdentifier.parent; + + if (!arkts.isCallExpression(parentNode) || !arkts.isIdentifier(parentNode.callee)) { + return; + } + let reportFlag: boolean = false; + // If the BlockStatement contains a child component that should not exist under the component, an error will be reported + parentNode.arguments.forEach((argument) => { + if ( + !arkts.isArrowFunctionExpression(argument) || + !argument.function.body || + !arkts.isBlockStatement(argument.function.body) + ) { + return; + } + argument.function.body.statements.forEach((statement) => { + const childComponentNode = findChildComponentNode(statement); + if (!childComponentNode) { + return; + } + const childComponentName = childComponentNode.name; + if ( + childComponentName === '' || + childComponentNames.includes(childComponentName) || + !isBuiltInComponent.bind(this)(childComponentNode) + ) { + return; + } + reportFlag = true; + reportDelegateChildrenComponentChildren.bind(this)(childComponentNode, childComponentName, componentName); + }); + }); + if (reportFlag) { + this.report({ + node: componentIdentifier, + level: LogType.ERROR, + message: `The component '${componentName}' can only have the child component '${listToString( + childComponentNames + )}'.`, + }); + } +} + +function findChildComponentNode(stmt: arkts.AstNode): arkts.Identifier | undefined { + if ( + !arkts.isExpressionStatement(stmt) || + !stmt.expression || + !arkts.isCallExpression(stmt.expression) || + !stmt.expression.callee + ) { + return undefined; + } + if (arkts.isIdentifier(stmt.expression.callee)) { + return stmt.expression.callee; + } + if ( + arkts.isMemberExpression(stmt.expression.callee) && + arkts.isCallExpression(stmt.expression.callee.object) && + arkts.isIdentifier(stmt.expression.callee.object.callee) + ) { + return stmt.expression.callee.object.callee; + } + return undefined; +} + +function reportDelegateChildrenComponentChildren( + this: BaseValidator, + childComponentNode: arkts.Identifier, + childComponentName: string, + componentName: string +): void { + this.report({ + node: childComponentNode, + level: LogType.ERROR, + message: `The '${childComponentName}' component cannot be a child component of the ${componentName} component.`, + }); +} + +function checkSingleChildComponent( + this: BaseValidator, + componentIdentifier: arkts.Identifier, + componentName: string +): void { + if (!componentIdentifier.parent) { + return; + } + const parentNode = componentIdentifier.parent; + if (!arkts.isCallExpression(parentNode)) { + return; + } + // If there is more than one subComponent in the BlockStatement, an error is reported + parentNode.arguments.forEach((argument) => { + if ( + !arkts.isArrowFunctionExpression(argument) || + !argument.function.body || + !arkts.isBlockStatement(argument.function.body) + ) { + return; + } + if (argument.function.body.statements.length <= SINGLE_CHILD_COMPONENT) { + return; + } + this.report({ + node: componentIdentifier, + level: LogType.ERROR, + message: `The '${componentName}' component can have only one child component.`, + }); + }); +} + +function checkNoChildComponent( + this: BaseValidator, + componentIdentifier: arkts.Identifier, + componentName: string +): void { + if (!componentIdentifier.parent) { + return; + } + let parentNode = componentIdentifier.parent; + if (!arkts.isCallExpression(parentNode)) { + return; + } + // If there are child components in arguments, an error will be reported + parentNode.arguments.forEach((argument) => { + if ( + !arkts.isArrowFunctionExpression(argument) || + !argument.function.body || + !arkts.isBlockStatement(argument.function.body) + ) { + return; + } + if (argument.function.body.statements.length === 0) { + return; + } + this.report({ + node: componentIdentifier, + level: LogType.ERROR, + message: `The component '${componentName}' can't have any child.`, + }); + }); +} + +function isBuiltInComponent( + this: BaseValidator, + componentIdentifier: arkts.Identifier +): boolean { + const componentsInfo = MetaDataCollector.getInstance().componentsInfo; + if (!componentsInfo) { + return false; + } + if (!isBuiltInDeclaration(componentIdentifier)) { + return false; + } + return ( + componentsInfo.containerComponents.includes(componentIdentifier.name) || + componentsInfo.atomicComponents.includes(componentIdentifier.name) + ); +} + +function listToString(strList: string[]): string { + return strList.length > 1 ? `${strList.join(',')}` : strList.join(''); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-reuse-component.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-reuse-component.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e8ffbcd2310342a213814157dc7c0cfdefd1f41 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-nested-reuse-component.ts @@ -0,0 +1,129 @@ +/* + * 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 { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkNestedReuseComponent = performanceLog( + _checkNestedReuseComponent, + getPerfName([0, 0, 0, 0, 0], 'checkNestedReuseComponent') +); + +const TEMPLATE: string = 'template'; +const REPEAT: string = 'Repeat'; + +/** + * 校验规则:用于验证可重用组件的嵌套用法。 + * 1. `@Component`组件不能包含`@ReusableV2`修饰的组件 + * 2. `@Reusable`组件不能包含`@ReusableV2`修饰的组件 + * 3. `@ReusableV2`组件不能包含`@Reusable`修饰的组件 + * 4. `Repeat`组件的`template`属性不能包含任何用`@ReusableV2装饰`的自定义组件。 + * + * 校验等级:error + */ +function _checkNestedReuseComponent( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + // If a non-custom component is called and is not in the custom component, it returns directly + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + const fromComponent: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasComponent; + const fromReusable: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasReusable; + const fromReusableV2: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasReusableV2; + const isReusableCall: boolean = !!metadata.structDeclInfo?.annotationInfo?.hasReusable; + const isReusableV2Call: boolean = !!metadata.structDeclInfo?.annotationInfo?.hasReusableV2; + const callExpression = arkts.unpackNonNullableNode(metadata.ptr!); + const { hasRepeat, hasTemplate } = checkHasRepeatOrTemplate(callExpression); + + // `@Component`组件不能包含`@ReusableV2`修饰的组件。(如果有`@Reusable`,只报第二个错误) + if (fromComponent && !fromReusable && isReusableV2Call) { + this.report({ + node: callExpression, + level: LogType.ERROR, + message: `A custom component decorated with @Component cannot contain child components decorated with @ReusableV2.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(callExpression), `Remove the component`), + }); + } + // `@Reusable`组件不能包含`@ReusableV2`修饰的组件 + if (fromReusable && isReusableV2Call) { + this.report({ + node: callExpression, + level: LogType.ERROR, + message: `A custom component decorated with @Reusable cannot contain child components decorated with @ReusableV2.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(callExpression), `Remove the component`), + }); + } + // `@ReusableV2`组件不能包含`@Reusable`修饰的组件 + if (fromReusableV2 && isReusableCall) { + this.report({ + node: callExpression, + level: LogType.ERROR, + message: `A custom component decorated with @ReusableV2 cannot contain child components decorated with @Reusable.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(callExpression), `Remove the component`), + }); + } + // `Repeat`组件的`template`属性不能包含任何用`@ReusableV2装饰`的自定义组件。 + if (hasRepeat && hasTemplate && isReusableV2Call) { + this.report({ + node: callExpression, + level: LogType.ERROR, + message: `The template attribute of the Repeat component cannot contain any custom component decorated with @ReusableV2.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(callExpression), `Remove the component`), + }); + } +} + +function checkHasRepeatOrTemplate(node: arkts.CallExpression): { hasRepeat: boolean; hasTemplate: boolean } { + let hasRepeat: boolean = false; + let hasTemplate: boolean = false; + let prevCall: arkts.CallExpression = node; + let currParent: arkts.AstNode | undefined = node.parent; + while (!!currParent) { + if (arkts.isCallExpression(currParent)) { + if (!currParent.callee?.findNodeInInnerChild(prevCall)) { + break; + } + prevCall = currParent; + } + currParent = currParent.parent; + } + if (!currParent || !arkts.isCallExpression(currParent) || !arkts.isMemberExpression(currParent.callee)) { + return { hasRepeat, hasTemplate }; + } + if ( + currParent.callee.property && + arkts.isIdentifier(currParent.callee.property) && + currParent.callee.property.name === TEMPLATE + ) { + hasTemplate = true; + } + if ( + currParent.callee.object && + arkts.isCallExpression(currParent.callee.object) && + currParent.callee.object.callee && + arkts.isIdentifier(currParent.callee.object.callee) && + currParent.callee.object.callee.name === REPEAT + ) { + hasRepeat = true; + } + return { hasRepeat, hasTemplate }; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-child-in-button.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-child-in-button.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2ef4c2fe9dea82e0fdb0339469696c5a12a66b5 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-child-in-button.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 { BaseValidator } from '../base'; +import { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkNoChildInButton = performanceLog( + _checkNoChildInButton, + getPerfName([0, 0, 0, 0, 0], 'checkNoChildInButton') +); + +const BUTTON: string = 'Button'; + +/** + * 校验规则:用于验证使用Button组件时包含子组价的错误用法。 + * 1. 带有 label 参数的 Button 组件不能包含任何子节点(参数只校验StringLiteral类型) + * + * 校验等级:error + */ +function _checkNoChildInButton(this: BaseValidator, node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // If it's a custom component or the name isn't button, it returns + if (metadata.structDeclInfo || !metadata.fromStructInfo || metadata.declName !== BUTTON) { + return; + } + if (node.arguments.length < 2) { + return; + } + // 带有 label 参数的 Button 组件不能包含任何子节点(参数只校验StringLiteral类型) + if (arkts.isStringLiteral(node.arguments[0]) && arkts.isArrowFunctionExpression(node.arguments[1])) { + this.report({ + node: node, + level: LogType.ERROR, + message: `The Button component with a label parameter can not have any child.`, + suggestion: createSuggestion('', ...getPositionRangeFromNode(node.arguments[1]), `Remove child components`), + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-id.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-id.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1ca1e1e0fb9730c32f2b5d482cc191be1404088 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-id.ts @@ -0,0 +1,110 @@ +/* + * 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 { CallInfo } from '../../records'; +import { findRootCallee } from '../../utils'; +import { ChainingCallDataSource } from '../../chaining-call-data-source'; +import { LogType } from '../../../../common/predefines'; +import { + checkIsCallFromInnerComponentOrExtendFromInfo, + checkIsValidChainingDataSource, + getCurrentFilePath, +} from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkNoDuplicateId = performanceLog( + _checkNoDuplicateId, + getPerfName([0, 0, 0, 0, 0], 'checkNoDuplicateId') +); + +export function resetNoDuplicateId(): void { + usedIds.clear(); +} + +interface IdInfo { + value: string; + node: arkts.AstNode; +} + +const ID_NAME: string = 'id'; + +const usedIds: Map = new Map(); + +/** + * 校验规则:用于验证组件的唯一标识符(ID) + * 1. 组件的唯一标识符(ID)不可重复 + * + * 校验等级:error + */ +function _checkNoDuplicateId(this: BaseValidator, node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // Check whether it is from inner components or from `@AnimatableExtend` + if (!checkIsCallFromInnerComponentOrExtendFromInfo(metadata)) { + return; + } + // Check whether it has chaining calls + if (!metadata.chainingCallInfos || metadata.chainingCallInfos.length === 0) { + return; + } + // Check whether chaining data is collected correctly + const chainingDataSource = ChainingCallDataSource.getInstance(); + if (!checkIsValidChainingDataSource(chainingDataSource, metadata)) { + return; + } + for (let idx = 0; idx < chainingDataSource.chainingCalls.length; idx++) { + const chainCall = chainingDataSource.chainingCalls.at(idx); + const chainingCallInfo = chainingDataSource.chainingCallInfos.at(idx); + if (!chainCall || !chainingCallInfo) { + break; + } + const callName = chainingCallInfo.callName!; + if (callName !== ID_NAME) { + continue; + } + const strArg = chainCall.arguments.find(arkts.isStringLiteral); + const value = strArg?.str; + if (!value) { + continue; + } + // 组件的唯一标识符(ID)不可重复 + const rootCallee = findRootCallee(chainCall.callee)!; + const cacheIdInfo = usedIds.get(value); + if (!!cacheIdInfo && cacheIdInfo.node.peer !== rootCallee.peer) { + reportDuplicatedId.bind(this)(rootCallee, value); + } else { + usedIds.set(value, { value, node: rootCallee }); + } + } +} + +function reportDuplicatedId( + this: BaseValidator, + callee: arkts.AstNode, + id: string +): void { + const path = getCurrentFilePath(callee); + if (!path) { + return; + } + const line = callee.startPosition.getLine() + 1; + const column = callee.startPosition.getCol(); + this.report({ + node: callee, + level: LogType.WARN, + message: `The current component id "${id}" is duplicate with ${path}:${line}:${column}.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-preview.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-preview.ts new file mode 100644 index 0000000000000000000000000000000000000000..195db8a743600b3734aeb76f74020e5e1b5c84f5 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-duplicate-preview.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 { BaseValidator } from '../base'; +import { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromAnnotation } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkNoDuplicatePreview = performanceLog( + _checkNoDuplicatePreview, + getPerfName([0, 0, 0, 0, 0], 'checkNoDuplicatePreview') +); + +export function resetNoDuplicatePreview(this: BaseValidator): void { + if (previewAnnotations.length > MAX_PREVIEW_DECORATOR_COUNT) { + previewAnnotations.forEach((annotation) => { + this.report({ + node: annotation, + level: LogType.ERROR, + message: `A page can contain at most 10 '@Preview' annotations.`, + suggestion: createSuggestion( + ``, + ...getPositionRangeFromAnnotation(annotation), + `Remove the duplicate 'Preview' annotation` + ), + }); + }); + } + previewAnnotations = []; +} + +const MAX_PREVIEW_DECORATOR_COUNT = 10; + +let previewAnnotations: arkts.AnnotationUsage[] = []; + +/** + * 校验规则:一个ArkTS文件最多可以包含10个`@Preview`装饰器。 + * + * 校验等级:error + */ +function _checkNoDuplicatePreview( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + if (!metadata.annotationInfo?.hasPreview) { + return; + } + previewAnnotations.push(metadata.annotations?.Preview!); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-prop-link-objectlink-in-entry.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-prop-link-objectlink-in-entry.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8da45ba0a588d98c7f6e802748deaa9c46f034b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-prop-link-objectlink-in-entry.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 { StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromAnnotation } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkNoPropLinkObjectlinkInEntry = performanceLog( + _checkNoPropLinkObjectlinkInEntry, + getPerfName([0, 0, 0, 0, 0], 'checkNoPropLinkObjectlinkInEntry') +); + +const invalidDecorators = [DecoratorNames.PROP_REF, DecoratorNames.LINK, DecoratorNames.OBJECT_LINK]; + +/** + * 校验规则:用于检验`@Entry` 组件属性的装饰器,防止某些特定的装饰器在入口组件中使用。 + * 1. `@PropRef`、`@Link`和`@ObjectLink`装饰器不能在`@Entry`中使用 + * + * 校验等级:warn + */ +function _checkNoPropLinkObjectlinkInEntry( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo || !metadata.structInfo.annotationInfo?.hasEntry) { + return; + } + // `@PropRef`、`@Link`和`@ObjectLink`装饰器不能在`@Entry`中使用 + invalidDecorators.forEach((decoratorName) => { + const invalidAnnotationNode = metadata.annotations?.[decoratorName]; + if (!invalidAnnotationNode) { + return; + } + const componentName = metadata.structInfo?.name; + const propertyName = metadata.name; + this.report({ + node: invalidAnnotationNode, + level: LogType.WARN, + message: `The '@Entry' component '${componentName}' cannot have the '@${decoratorName}' property '${propertyName}'.`, + suggestion: createSuggestion( + ``, + ...getPositionRangeFromAnnotation(invalidAnnotationNode), + `Remove the annotation` + ), + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-same-as-built-in-attribute.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-same-as-built-in-attribute.ts new file mode 100644 index 0000000000000000000000000000000000000000..282f1857ed0b5bdc895cc71007d0a99824210171 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-no-same-as-built-in-attribute.ts @@ -0,0 +1,52 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { MetaDataCollector } from '../../../../common/metadata-collector'; + +export const checkNoSameAsBuiltInAttribute = performanceLog( + _checkNoSameAsBuiltInAttribute, + getPerfName([0, 0, 0, 0, 0], 'checkNoSameAsBuiltInAttribute') +); + +/** + * 校验规则:用于验证当前自定义的Struct名称是否与内置属性名称相同。 + * 1. 自定义组件Struct的名称不能与内置属性的名称相同。 + * + * 校验等级:error + */ +function _checkNoSameAsBuiltInAttribute( + this: BaseValidator, + struct: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const componentsInfo = MetaDataCollector.getInstance().componentsInfo; + if (!componentsInfo || !metadata.name || !struct.definition?.ident) { + return; + } + const structName = metadata.name; + // 自定义组件Struct的名称不能与内置属性的名称相同 + if (componentsInfo.builtInAttributes.includes(structName)) { + this.report({ + node: struct.definition.ident, + level: LogType.ERROR, + message: `The struct '${structName}' cannot have the same name as the built-in attribute '${structName}'.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-heritage-compatible.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-heritage-compatible.ts new file mode 100644 index 0000000000000000000000000000000000000000..e84548e5c50c28bee5f74b6f2d733b226bef37d7 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-heritage-compatible.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 { BaseValidator } from '../base'; +import { NormalClassInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getAnnotationUsageByName } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkObservedHeritageCompatible = performanceLog( + _checkObservedHeritageCompatible, + getPerfName([0, 0, 0, 0, 0], 'checkObservedHeritageCompatible') +); + +/** + * 校验规则:用于验证类继承过程中的`@Observed`和`@ObservedV2`装饰器混用。 + * 1. 当前类是由`@ObservedV2`装饰的,它不能继承`@Observed`装饰的类。 + * 2. 当前类是由`@Observed`装饰的,它不能继承`@ObservedV2`装饰的类。 + * + * 校验等级:error + */ +function _checkObservedHeritageCompatible( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const hasObserved = !!metadata.annotationInfo?.hasObserved; + const hasObservedV2 = !!metadata.annotationInfo?.hasObservedV2; + const hasObservedInSuper = hasTargetAnnotationInSuperClass(node, DecoratorNames.OBSERVED); + const hasObservedV2InSuper = hasTargetAnnotationInSuperClass(node, DecoratorNames.OBSERVED_V2); + if (hasObserved && hasObservedV2) { + return; + } + if (hasObserved && hasObservedV2InSuper) { + const annotation = metadata.annotations?.[DecoratorNames.OBSERVED]!; + this.report({ + node: annotation, + level: LogType.ERROR, + message: `A class decorated by '@Observed' cannot inherit from a class decorated by '@ObservedV2'.`, + }); + } + if (hasObservedV2 && hasObservedInSuper) { + const annotation = metadata.annotations?.[DecoratorNames.OBSERVED_V2]!; + this.report({ + node: annotation, + level: LogType.ERROR, + message: `A class decorated by '@ObservedV2' cannot inherit from a class decorated by '@Observed'.`, + }); + } +} + +function hasTargetAnnotationInSuperClass(node: arkts.ClassDeclaration, annotationName: string): boolean { + if (!node.definition || !node.definition.super) { + return false; + } + if (arkts.isETSTypeReference(node.definition.super)) { + if (!node.definition.super.part || !arkts.isETSTypeReferencePart(node.definition?.super.part)) { + return false; + } + if (!node.definition.super.part.name || !arkts.isIdentifier(node.definition.super.part.name)) { + return false; + } + const superClassDefinition = arkts.getPeerIdentifierDecl(node.definition.super.part.name.peer); + if (!superClassDefinition || !arkts.isClassDefinition(superClassDefinition)) { + return false; + } + return !!getAnnotationUsageByName(superClassDefinition.annotations, annotationName); + } + return false; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-observedV2.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-observedV2.ts new file mode 100644 index 0000000000000000000000000000000000000000..686ac692af26bcf66972dd1c5485ff98230ad181 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observed-observedV2.ts @@ -0,0 +1,59 @@ +/* + * 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 { NormalClassInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkObservedObservedV2 = performanceLog( + _checkObservedObservedV2, + getPerfName([0, 0, 0, 0, 0], 'checkObservedObservedV2') +); + +/** + * 校验规则:用于验证使用 `@Observed` 装饰器和`@ObserverdV2`装饰器混合使用的错误情况。 + * 1. 一个class不能同时使用`@Observed` 装饰器和`@ObserverdV2`装饰器装饰。 + * + * 校验等级:error + */ +function _checkObservedObservedV2( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const hasObserved = !!metadata.annotationInfo?.hasObserved; + const hasObservedV2 = !!metadata.annotationInfo?.hasObservedV2; + // 一个class不能同时使用`@Observed` 装饰器和`@ObserverdV2`装饰器装饰 + if (hasObserved && hasObservedV2) { + const firstObservedDecorator = node.definition?.annotations.find((annotation) => { + if (annotation.expr && arkts.isIdentifier(annotation.expr)) { + return ( + annotation.expr.name === DecoratorNames.OBSERVED || + annotation.expr.name === DecoratorNames.OBSERVED_V2 + ); + } + }); + if (!firstObservedDecorator) { + return; + } + this.report({ + node: firstObservedDecorator, + level: LogType.ERROR, + message: `A class can not be decorated by '@Observed' and '@ObservedV2' at the same time.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observedV2-trace-usage-validation.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observedV2-trace-usage-validation.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd19fbcff0fc1d9726ed91298ce61c5e2c9832fa --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-observedV2-trace-usage-validation.ts @@ -0,0 +1,318 @@ +/* + * 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 type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { + CustomComponentInfo, + FunctionInfo, + GLobalPropertyInfo, + NormalClassInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + NormalInterfaceInfo, + StructMethodInfo, + StructPropertyInfo, +} from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { + createSuggestion, + getPositionRangeFromAnnotation, + getPositionRangeFromNode, +} from '../../../../common/log-collector'; +import { + checkIsGlobalFunctionFromInfo, + checkIsNormalClassMethodFromInfo, + checkIsNormalClassPropertyFromInfo, + checkIsStructMethodFromInfo, + checkIsStructPropertyFromInfo, +} from '../../../../collectors/ui-collectors/utils'; +import { getAnnotationUsageByName } from '../utils'; +import { checkIsCustomComponentFromInfo } from '../../../../collectors/ui-collectors/utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkObservedV2TraceUsageValidation = performanceLog( + _checkObservedV2TraceUsageValidation, + getPerfName([0, 0, 0, 0, 0], 'checkObservedV2TraceUsageValidation') +); + +const OBSERVED_V2_DECORATOR_ERROR = `The '@ObservedV2' annotation can only be used in 'class'.`; +const TRACE_DECORATOR_ERROR = `The '@Trace' annotation can only be used in 'class'.`; +const TRACE_MEMBER_VARIABLE_ERROR = `The '@Trace' annotation can only decorate member 'variables' within a 'class' decorated with '@ObservedV2'.`; + +const REMOVE_OBSERVED_V2 = `Remove the @ObservedV2 annotation`; +const REMOVE_TRACE = `Remove the @Trace annotation`; +const ADD_OBSERVED_V2 = `Add @ObservedV2 annotation`; +const CHANGE_OBSERVED = `Change @Observed to @ObservedV2`; + +/** + * 校验规则:用于验证`@ObservedV2`、`@Trace`装饰器时需要遵循的具体约束和条件 + * 1. `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + * 2. `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + * 3. `@Trace` 只能用于被 `@ObservedV2` 装饰的类中的成员变量。 + * + * 校验等级:error + */ +function _checkObservedV2TraceUsageValidation(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkRuleInClassProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkRuleInMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION, checkInvalidObservedV2AndTraceInInterface], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, checkRuleInClassDeclaration], +]); + +function checkRuleInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructPropertyFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInStructProperty.bind(this)(node); + } else if (checkIsNormalClassPropertyFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInClassProperty.bind(this)(node); + } else { + checkInvalidObservedV2AndTraceInGlobalProperty.bind(this)(node); + } +} + +function checkRuleInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructMethodFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInStructMethod.bind(this)(node); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInClassMethod.bind(this)(node); + } + if (checkIsGlobalFunctionFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInFunction.bind(this)(node); + } +} + +function checkRuleInClassDeclaration( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsCustomComponentFromInfo(metadata)) { + checkInvalidObservedV2AndTraceInStruct.bind(this)(node); + } else { + checkInvalidTraceInClass.bind(this)(node); + } +} + +function checkInvalidObservedV2AndTraceInStructProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 只能用于被 `@ObservedV2` 装饰的类中的成员变量。 + if (!metadata.ignoredAnnotationInfo?.hasTrace || metadata.classInfo?.annotationInfo?.hasObservedV2) { + return; + } + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + if (!metadata.classInfo?.annotationInfo?.hasObserved) { + const classDeclarations = arkts.unpackNonNullableNode(metadata.classInfo?.definitionPtr!).parent; + if (classDeclarations) { + let startPosition = classDeclarations.startPosition; + this.report({ + node: traceNode, + level: LogType.ERROR, + message: TRACE_MEMBER_VARIABLE_ERROR, + suggestion: createSuggestion( + `@${DecoratorNames.OBSERVED_V2}\n`, + startPosition, + startPosition, + ADD_OBSERVED_V2 + ), + }); + } + } + if (metadata.classInfo?.annotationInfo?.hasObserved) { + const observedNode = metadata.classInfo.annotations?.[DecoratorNames.OBSERVED]!; + this.report({ + node: traceNode, + level: LogType.ERROR, + message: TRACE_MEMBER_VARIABLE_ERROR, + suggestion: createSuggestion( + `${DecoratorNames.OBSERVED_V2}`, + ...getPositionRangeFromNode(observedNode), + CHANGE_OBSERVED + ), + }); + } +} + +function checkInvalidObservedV2AndTraceInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInFunction( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInClassMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 只能用于被 `@ObservedV2` 装饰的类中的成员变量。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_MEMBER_VARIABLE_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInInterface( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!arkts.isTSInterfaceDeclaration(node)) { + return; + } + const observedV2Node = getAnnotationUsageByName(node.annotations, DecoratorNames.OBSERVED_V2); + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (observedV2Node) { + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + const traceNode = getAnnotationUsageByName(node.annotations, DecoratorNames.TRACE); + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (traceNode) { + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInGlobalProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidObservedV2AndTraceInStruct( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@ObservedV2` 装饰器只能作用在 `class` 上,不能用于function、interface、struct、property(struct/class/global)、method(struct/class)上。 + if (metadata.ignoredAnnotationInfo?.hasObservedV2) { + const observedV2Node = metadata.ignoredAnnotations?.[DecoratorNames.OBSERVED_V2]!; + reportErrorWithRemoveAnnotationFix.bind(this)(observedV2Node, OBSERVED_V2_DECORATOR_ERROR, REMOVE_OBSERVED_V2); + } + // `@Trace` 装饰器必须定义在一个 `class` 内部,不能用于function、interface、struct、property(struct/global)、method(struct)上。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_DECORATOR_ERROR, REMOVE_TRACE); + } +} + +function checkInvalidTraceInClass( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Trace` 只能用于被 `@ObservedV2` 装饰的类中的成员变量。 + if (metadata.ignoredAnnotationInfo?.hasTrace) { + const traceNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACE]!; + reportErrorWithRemoveAnnotationFix.bind(this)(traceNode, TRACE_MEMBER_VARIABLE_ERROR, REMOVE_TRACE); + } +} + +function reportErrorWithRemoveAnnotationFix( + this: BaseValidator, + errorNode: arkts.AnnotationUsage, + message: string, + fixTitle: string +): void { + this.report({ + node: errorNode, + level: LogType.ERROR, + message: message, + suggestion: createSuggestion(``, ...getPositionRangeFromAnnotation(errorNode), fixTitle), + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-old-new-decorator-mix-use.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-old-new-decorator-mix-use.ts new file mode 100644 index 0000000000000000000000000000000000000000..c66bfc77f9029d2c14a9037ee517690fd87ed1ef --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-old-new-decorator-mix-use.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 { BaseValidator } from '../base'; +import { StructPropertyInfo, NormalClassPropertyInfo } from '../../records'; +import { DecoratorNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { checkIsNormalClassPropertyFromInfo, checkIsStructPropertyFromInfo } from '../../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkOldNewDecoratorMixUse = performanceLog( + _checkOldNewDecoratorMixUse, + getPerfName([0, 0, 0, 0, 0], 'checkOldNewDecoratorMixUse') +); + +const oldV1Annotations: string[] = [ + DecoratorNames.STATE, + DecoratorNames.PROP_REF, + DecoratorNames.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.WATCH, + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.OBJECT_LINK, +]; + +const newV2Annotations: string[] = [ + DecoratorNames.LOCAL, + DecoratorNames.PARAM, + DecoratorNames.ONCE, + DecoratorNames.EVENT, + DecoratorNames.MONITOR, + DecoratorNames.PROVIDER, + DecoratorNames.CONSUMER, + DecoratorNames.COMPUTED, +]; + +const notAllowedInClass: string[] = [DecoratorNames.LOCAL, DecoratorNames.PARAM]; + +/** + * 校验规则:用于检查新旧装饰器的使用情况 + * 注:`@Component`与`@ComponentV2`同时使用、或都不使用的情况下,报其他错误本规则不报错 + * 1. 旧装饰器只能用于`@Component`组件 + * 2. 新装饰器只能用于`@ComponentV2`组件 + * + * 校验等级:error + */ +function _checkOldNewDecoratorMixUse( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (checkIsStructPropertyFromInfo(metadata)) { + checkOldNewDecoratorMixUseInStruct.bind(this)(classProperty); + } else if (checkIsNormalClassPropertyFromInfo(metadata)) { + checkOldNewDecoratorMixUseInClass.bind(this)(classProperty); + } +} + +function checkOldNewDecoratorMixUseInStruct( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + const fromComponent: boolean = !!metadata.structInfo?.annotationInfo?.hasComponent; + const fromComponentV2: boolean = !!metadata.structInfo?.annotationInfo?.hasComponentV2; + // 新装饰器只能用于`@ComponentV2`组件 + if (fromComponent && !fromComponentV2) { + const componentAnnotations = metadata.structInfo?.annotations?.[StructDecoratorNames.COMPONENT]!; + newV2Annotations.forEach((decoratorName) => { + const annotation = metadata.annotations?.[decoratorName]; + if (!annotation) { + return; + } + this.report({ + node: annotation, + level: LogType.ERROR, + message: `The '@${decoratorName}' annotation can only be used in a 'struct' decorated with '@ComponentV2'.`, + suggestion: createSuggestion( + `${StructDecoratorNames.COMPONENT_V2}`, + ...getPositionRangeFromNode(componentAnnotations), + `Change @Component to @ComponentV2` + ), + }); + }); + } + // 旧装饰器只能用于`@Component`组件 + if (fromComponentV2 && !fromComponent) { + const componentV2Annotations = metadata.structInfo?.annotations?.[StructDecoratorNames.COMPONENT_V2]!; + oldV1Annotations.forEach((decoratorName) => { + const annotation = metadata.annotations?.[decoratorName]; + if (!annotation) { + return; + } + this.report({ + node: annotation, + level: LogType.ERROR, + message: `The '@${decoratorName}' annotation can only be used in a 'struct' decorated with '@Component'.`, + suggestion: createSuggestion( + `${StructDecoratorNames.COMPONENT}`, + ...getPositionRangeFromNode(componentV2Annotations), + `Change @ComponentV2 to @Component` + ), + }); + }); + } +} + +function checkOldNewDecoratorMixUseInClass( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + notAllowedInClass.forEach((decoratorName) => { + const annotation = metadata.ignoredAnnotations?.[decoratorName]; + if (!annotation) { + return; + } + this.report({ + node: annotation, + level: LogType.ERROR, + message: `The '@${decoratorName}' annotation can only be used in a 'struct' decorated with '@ComponentV2'.`, + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-once-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-once-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd790a059615cb60bb51a5c43e268f2ecbbeb2d5 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-once-decorator.ts @@ -0,0 +1,194 @@ +/* + * 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 type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { NormalClassMethodInfo, NormalClassPropertyInfo, StructMethodInfo, StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromAnnotation } from '../../../../common/log-collector'; +import { + checkIsNormalClassMethodFromInfo, + checkIsNormalClassPropertyFromInfo, + checkIsStructMethodFromInfo, + checkIsStructPropertyFromInfo, +} from '../../../../collectors/ui-collectors/utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkOnceDecorator = performanceLog( + _checkOnceDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkOnceDecorator') +); + +const INVALID_MEMBER_DECORATE = `'@Once' can only decorate member property.`; +const INVALID_WITHOUT_PARAM = `When a variable decorated with '@Once', it must also be decorated with '@Param'.`; +const INVALID_NOT_IN_STRUCT = `The '@Once' annotation can only be used with 'struct'.`; + +const REMOVE_ANNOTATION = `Remove the annotation`; +const ADD_PARAM_ANNOTATION = `Add @Param annotation`; + +/** + * 校验规则:用于验证`@Once` 装饰器时需要遵循的具体约束和条件 + * 1.`@Once` 装饰器用在使用了 `@ComponentV2` 装饰的 `struct` 中(已由check-old-new-decorator-mix-use校验) + * 2.`@Once` 只能装饰成员属性 + * 3.使用 `@Once` 必须同时使用 `@Param` + * 4.`@Once` 只能在 `struct` 中使用 + * + * 校验等级:error + */ +function _checkOnceDecorator(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkOnceInMethod], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkOnceInProperty], +]); + +function checkOnceInMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructMethodFromInfo(metadata)) { + checkOnceInStructMethod.bind(this)(node); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkOnceInClassMethod.bind(this)(node); + } +} + +function checkOnceInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.ignoredAnnotationInfo?.hasOnce) { + return; + } + const onceAnnotation = metadata.ignoredAnnotations?.[DecoratorNames.ONCE]; + if (!onceAnnotation) { + return; + } + // 使用 `@Once` 必须同时使用 `@Param` + if (!metadata.ignoredAnnotationInfo?.hasParam) { + reportOnceWithoutParam.bind(this)(onceAnnotation); + } else { + // `@Once` 只能装饰成员属性 + reportErrorWithDeleteFix.bind(this)(onceAnnotation, INVALID_MEMBER_DECORATE); + } +} + +function checkOnceInClassMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.ignoredAnnotationInfo?.hasOnce) { + return; + } + const onceAnnotation = metadata.ignoredAnnotations?.[DecoratorNames.ONCE]; + if (!onceAnnotation) { + return; + } + // 使用 `@Once` 必须同时使用 `@Param` + if (!metadata.ignoredAnnotationInfo?.hasParam) { + reportOnceWithoutParam.bind(this)(onceAnnotation); + } else { + // `@Once` 只能在 `struct` 中使用 + reportErrorWithDeleteFix.bind(this)(onceAnnotation, INVALID_NOT_IN_STRUCT); + } +} + +function checkOnceInProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructPropertyFromInfo(metadata)) { + checkOnceInStructProperty.bind(this)(node); + } + if (checkIsNormalClassPropertyFromInfo(metadata)) { + checkOnceInClassProperty.bind(this)(node); + } +} + +function checkOnceInStructProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.annotationInfo?.hasOnce) { + return; + } + const onceAnnotation = metadata.annotations?.[DecoratorNames.ONCE]; + if (!onceAnnotation) { + return; + } + // 使用 `@Once` 必须同时使用 `@Param` + if (!metadata.annotationInfo?.hasParam) { + reportOnceWithoutParam.bind(this)(onceAnnotation); + } +} + +function checkOnceInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!metadata.ignoredAnnotationInfo?.hasOnce) { + return; + } + const onceAnnotation = metadata.ignoredAnnotations?.[DecoratorNames.ONCE]; + if (!onceAnnotation) { + return; + } + // 使用 `@Once` 必须同时使用 `@Param` + if (!metadata.ignoredAnnotationInfo?.hasParam) { + reportOnceWithoutParam.bind(this)(onceAnnotation); + } else { + // `@Once` 只能在 `struct` 中使用 + reportErrorWithDeleteFix.bind(this)(onceAnnotation, INVALID_NOT_IN_STRUCT); + } +} + +function reportOnceWithoutParam( + this: BaseValidator, + onceAnnotation: arkts.AnnotationUsage +): void { + const endPosition = onceAnnotation.endPosition; + this.report({ + node: onceAnnotation, + message: INVALID_WITHOUT_PARAM, + level: LogType.ERROR, + suggestion: createSuggestion(` @${DecoratorNames.PARAM}`, endPosition, endPosition, ADD_PARAM_ANNOTATION), + }); +} + +function reportErrorWithDeleteFix( + this: BaseValidator, + onceAnnotation: arkts.AnnotationUsage, + message: string +): void { + this.report({ + node: onceAnnotation, + message: message, + level: LogType.ERROR, + suggestion: createSuggestion('', ...getPositionRangeFromAnnotation(onceAnnotation), REMOVE_ANNOTATION), + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-one-decorator-on-function-method.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-one-decorator-on-function-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ba809d8f72c5cb567a1a1023620d99665979926 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-one-decorator-on-function-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 { BaseValidator } from '../base'; +import { FunctionInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromAnnotation } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkOneDecoratorOnFunctionMethod = performanceLog( + _checkOneDecoratorOnFunctionMethod, + getPerfName([0, 0, 0, 0, 0], 'checkOneDecoratorOnFunctionMethod') +); + +const PARAM_THIS_NAME = '=t'; + +const REMOVE_ANNOTATION = `Remove the annotation`; + +/** + * 校验规则:用于验证只能装饰函数的装饰器 + * 1. 只有`@Builder`和`@AnimatableExtend`装饰器可以装饰函数 + * 2. `@AnimatableExtend` 装饰器只能用于带有 `this` 参数的函数 + * + * 校验等级:error + */ +function _checkOneDecoratorOnFunctionMethod( + this: BaseValidator, + node: arkts.MethodDefinition +): void { + const metadata = this.context ?? {}; + let ignoredAnnotationCount = 0; + // 只有`@Builder`和`@AnimatableExtend`装饰器可以装饰函数 + for (const key in metadata.ignoredAnnotations) { + const annotationNode = metadata.ignoredAnnotations?.[key]!; + this.report({ + node: annotationNode, + level: LogType.ERROR, + message: `A function can only be decorated by one of the '@AnimatableExtend' and '@Builder'.`, + suggestion: createSuggestion('', ...getPositionRangeFromAnnotation(annotationNode), REMOVE_ANNOTATION), + }); + ignoredAnnotationCount++; + } + // 只有`@Builder`和`@AnimatableExtend`装饰器可以装饰函数(同时装饰或有ignoredAnnotation时,Builder和AnimatableExtend自身也报错) + if ( + (metadata.annotationInfo?.hasAnimatableExtend && metadata.annotationInfo?.hasBuilder) || + ignoredAnnotationCount > 0 + ) { + for (const key in metadata.annotations) { + const annotationNode = metadata.annotations?.[key]!; + this.report({ + node: annotationNode, + level: LogType.ERROR, + message: `A function can only be decorated by one of the '@AnimatableExtend' and '@Builder'.`, + }); + } + } + // `@AnimatableExtend` 装饰器只能用于带有 `this` 参数的函数 + // if (metadata.annotationInfo?.hasAnimatableExtend && !hasThisParameter(node.funcExpr.scriptFunction)) { + if (metadata.annotationInfo?.hasAnimatableExtend && !hasThisParameter(node.function)) { + const annotationNode = metadata.annotations?.[DecoratorNames.ANIMATABLE_EXTEND]!; + this.report({ + node: annotationNode, + level: LogType.ERROR, + message: `When a function is decorated with "@AnimatableExtend", the first parameter must be 'this'.`, + suggestion: createSuggestion('', ...getPositionRangeFromAnnotation(annotationNode), REMOVE_ANNOTATION), + }); + } +} + +function hasThisParameter(member: arkts.ScriptFunction): boolean { + return member.params.some((param) => { + return ( + arkts.isETSParameterExpression(param) && + arkts.isIdentifier(param.ident) && + param.ident.name === PARAM_THIS_NAME + ); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-modifiers.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-modifiers.ts new file mode 100644 index 0000000000000000000000000000000000000000..e88216eaa87adbac19ee76654dd115fae24de0be --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-modifiers.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 { StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { isPrivateClassProperty, isProtectedClassProperty, isPublicClassProperty } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkPropertyModifiers = performanceLog( + _checkPropertyModifiers, + getPerfName([0, 0, 0, 0, 0], 'checkPropertyModifiers') +); + +const noPublicDecorators: string[] = [ + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.STORAGE_LINK, + DecoratorNames.LOCAL_STORAGE_LINK, +]; + +const noPrivateDecorators: string[] = [DecoratorNames.LINK, DecoratorNames.OBJECT_LINK]; + +/** + * 校验规则:用于约束属性访问修饰符的使用。 + * 1.`public`访问修饰符不能与`StorageLink`、`StorageProp`、`LocalStorageLink`、`LocalStorageProp`一起修饰属性。 + * 2.`private `访问修饰符不能与`Link `、`ObjectLink `一起修饰属性。 + * 3.`protected `访问修饰符不能修饰属性。 + * + * 校验等级:warn + */ + +function _checkPropertyModifiers( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo || node.isDefaultAccessModifier) { + return; + } + const propertyName = metadata.name; + if (!propertyName) { + return; + } + checkInvalidPublic.bind(this)(propertyName, node); + checkInvalidPrivate.bind(this)(propertyName, node); + checkInvalidProtected.bind(this)(node); +} + +function checkInvalidPublic( + this: BaseValidator, + propertyName: string, + member: arkts.ClassProperty +): void { + if (!isPublicClassProperty(member)) { + return; + } + let noPublicAnnotationName = ''; + const noPublicAnnotation = member.annotations.find((annotation) => { + if ( + annotation.expr && + arkts.isIdentifier(annotation.expr) && + noPublicDecorators.includes(annotation.expr.name) + ) { + noPublicAnnotationName = annotation.expr.name; + return true; + } + }); + if (!noPublicAnnotation || noPublicAnnotationName === '') { + return; + } + // `public`访问修饰符不能与`StorageLink`、`StorageProp`、`LocalStorageLink`、`LocalStorageProp`一起修饰属性。 + this.report({ + node: member, + level: LogType.WARN, + message: `The @${noPublicAnnotationName} decorated '${propertyName}' cannot be declared as public.`, + }); +} + +function checkInvalidPrivate( + this: BaseValidator, + propertyName: string, + member: arkts.ClassProperty +): void { + if (!isPrivateClassProperty(member)) { + return; + } + let noPrivateAnnotationName = ''; + const noPrivateAnnotation = member.annotations.find((annotation) => { + if ( + annotation.expr && + arkts.isIdentifier(annotation.expr) && + noPrivateDecorators.includes(annotation.expr.name) + ) { + noPrivateAnnotationName = annotation.expr.name; + return true; + } + }); + if (!noPrivateAnnotation || noPrivateAnnotationName === '') { + return; + } + // `private `访问修饰符不能与`Link `、`ObjectLink `一起修饰属性。 + this.report({ + node: member, + level: LogType.WARN, + message: `The @${noPrivateAnnotationName} decorated '${propertyName}' cannot be declared as private.`, + }); +} + +function checkInvalidProtected( + this: BaseValidator, + member: arkts.ClassProperty +): void { + if (!isProtectedClassProperty(member)) { + return; + } + // `protected `访问修饰符不能修饰属性。 + this.report({ + node: member, + level: LogType.WARN, + message: `The member attributes of a struct can not be protected.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-type.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..5dcecb7857ce0c0a38267c673410e3e44e40a427 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-property-type.ts @@ -0,0 +1,238 @@ +/* + * 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'; +import { TypeFlags, getAnnotationUsageByName } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkPropertyType = performanceLog(_checkPropertyType, getPerfName([0, 0, 0, 0, 0], 'checkPropertyType')); + +const propertyPropDecorator: string[] = [DecoratorNames.PROP_REF, DecoratorNames.STORAGE_PROP_REF]; + +const SimpleTypesUnSupported = [ + TypeFlags.Boolean, + TypeFlags.String, + TypeFlags.Number, + TypeFlags.Enum, + TypeFlags.BigInt, +]; + +const ARRAY_TYPES = ['Array', 'Map', 'Set', 'Date']; + +const PropErrorType = ['Any']; + +/** + * 校验规则:用于检验特定装饰器的类型。 + * 1. @ObjectLink 不能用于简单类型和被observeV2装饰的类。仅应用于由 @Observed 装饰或通过 makeV1Observed 初始化的类; + * 2. @PropRef 或 @StoragePropRef装饰的属性必须是字符串、数字、布尔值、枚举或对象类型; + * 3. @BuilderParam 属性只能由 @Builder 函数或 @Builder 方法本地初始化; + * + * 校验等级:error + */ +function _checkPropertyType( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo || !node.key || !arkts.isIdentifier(node.key) || !metadata.name || !node.typeAnnotation) { + return; + } + const propertyName = metadata.name; + const propertyType = node.typeAnnotation; + const annotationIdentifier = node.key; + // @ObjectLink 不能用于简单类型和被observeV2装饰的类。仅应用于由 @Observed 装饰或通过 makeV1Observed 初始化的类 + if (metadata.annotationInfo?.hasObjectLink && propertyType) { + validateObjectLinkPropertyType.bind(this)(propertyType, annotationIdentifier); + } + // @PropRef 或 @StoragePropRef装饰的属性必须是字符串、数字、布尔值、枚举或对象类型 + propertyPropDecorator.forEach((annotation) => { + if (!metadata.annotations?.[annotation]) { + return; + } + if ( + (arkts.isETSUnionType(propertyType) && !areAllUnionMembersNotAnyAndBigint(propertyType)) || + (!arkts.isETSUnionType(propertyType) && typeNodeIsAnyAndBigint(propertyType)) + ) { + this.report({ + node: annotationIdentifier, + level: LogType.ERROR, + message: `The '@${annotation}' decorated attribute '${propertyName}' must be of the string, number, boolean, enum or object type.`, + }); + } + }); + + // @BuilderParam 属性只能由 @Builder 函数或 @Builder 方法本地初始化 + if (!metadata.annotationInfo?.hasBuilderParam || !node.value) { + return; + } + let methodIdentifier: arkts.Identifier | undefined = undefined; + if (arkts.isIdentifier(node.value)) { + methodIdentifier = node.value; + } else if (arkts.isMemberExpression(node.value) && arkts.isIdentifier(node.value.property)) { + methodIdentifier = node.value.property; + } + const isMethodWithBuilder = methodIdentifier ? isMethodOrFunctionWithBuilderDecorator(methodIdentifier) : undefined; + if (!methodIdentifier || isMethodWithBuilder === false) { + this.report({ + node: node.key, + level: LogType.ERROR, + message: `'@BuilderParam' property can only be initialized by '@Builder' function or '@Builder' method in struct.`, + }); + } +} + +function validateObjectLinkPropertyType( + this: BaseValidator, + propertyType: arkts.TypeNode, + annotationIdentifier: arkts.Identifier +): void { + // @ObjectLink 不能用于简单类型和被observeV2装饰的类。仅应用于由 @Observed 装饰或通过 makeV1Observed 初始化的类 + if ( + arkts.isETSTypeReference(propertyType) && + propertyType.part && + propertyType.part.name && + arkts.isIdentifier(propertyType.part.name) + ) { + const propertyTypeName = propertyType.part.name.name; + if ( + checkTypeClassWithObservedV2(propertyType.part.name) || + SimpleTypesUnSupported.includes(propertyTypeName) || + PropErrorType.includes(propertyTypeName) + ) { + this.report({ + node: annotationIdentifier, + level: LogType.ERROR, + message: `'@ObjectLink' cannot be used with this type. Apply it only to classes decorated by '@Observed' or initialized using the return value of 'makeV1Observed'.`, + }); + } + } else if ( + arkts.nodeType(propertyType) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_STRING_LITERAL_TYPE || + arkts.nodeType(propertyType) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_NULL_TYPE || + arkts.nodeType(propertyType) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_BROKEN_TYPE_NODE || + arkts.isETSPrimitiveType(propertyType) || + arkts.isETSUndefinedType(propertyType) + ) { + this.report({ + node: annotationIdentifier, + level: LogType.ERROR, + message: `'@ObjectLink' cannot be used with this type. Apply it only to classes decorated by '@Observed' or initialized using the return value of 'makeV1Observed'.`, + }); + } + if (arkts.isETSUnionType(propertyType)) { + if (!areAllUnionMembersValid(propertyType)) { + this.report({ + node: annotationIdentifier, + level: LogType.ERROR, + message: `'@ObjectLink' cannot be used with this type. Apply it only to classes decorated by '@Observed' or initialized using the return value of 'makeV1Observed'.`, + }); + } + } +} + +function areAllUnionMembersNotAnyAndBigint(unionType: arkts.ETSUnionType): boolean { + const members = unionType.types; + for (const member of members) { + if ( + typeNodeIsAnyAndBigint(member) === true || + arkts.nodeType(member) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_BROKEN_TYPE_NODE + ) { + return false; + } + } + return true; +} + +function typeNodeIsAnyAndBigint(member: arkts.TypeNode): boolean | undefined { + if (arkts.isETSTypeReference(member) && member.part && member.part.name && arkts.isIdentifier(member.part.name)) { + const propertyTypeName = member.part.name.name; + if (propertyTypeName === PropErrorType[0] || propertyTypeName === TypeFlags.BigInt) { + return true; + } + } + return false; +} + +function isMethodOrFunctionWithBuilderDecorator(node: arkts.Identifier): boolean { + const methodDecl = arkts.getPeerIdentifierDecl(node.peer); + if ( + methodDecl && + arkts.isMethodDefinition(methodDecl) && + (getAnnotationUsageByName(methodDecl.function.annotations, DecoratorNames.BUILDER) + || getAnnotationUsageByName(methodDecl.function.annotations, DecoratorNames.LOCAL_BUILDER)) + ) { + return true; + } + return false; +} + +function checkTypeClassWithObservedV2(classExpr: arkts.Identifier): boolean | undefined { + let decl: arkts.AstNode | undefined; + if (!!classExpr) { + decl = arkts.getPeerIdentifierDecl(classExpr.peer); + } + if (!decl || !arkts.isClassDefinition(decl) || !decl.parent || !arkts.isClassDeclaration(decl.parent)) { + return undefined; + } + const classRecord = RecordBuilder.build(NormalClassRecord, decl.parent, { shouldIgnoreDecl: false }); + if (!classRecord.isCollected) { + classRecord.collect(decl.parent); + } + const classInfo = classRecord.toRecord(); + return !!classInfo?.annotationInfo?.hasObservedV2; +} + +// null、undefined与有效类型联合为有效,其余情况只要存在无效类型则无效。 +function areAllUnionMembersValid(unionType: arkts.ETSUnionType): boolean { + const members = unionType.types; + // At least one valid type All types must be allowed types and do not contain illegal combinations + let isValidType = false; + for (const member of members) { + if ( + arkts.isETSTypeReference(member) && + member.part && + member.part.name && + arkts.isIdentifier(member.part.name) + ) { + const propertyTypeIdentifier = member.part.name; + const propertyTypeName = member.part.name.name; + // If it's a simple type or ObservedV2, reject the entire union type outright + if ( + checkTypeClassWithObservedV2(propertyTypeIdentifier) || + SimpleTypesUnSupported.includes(propertyTypeName) || + PropErrorType.includes(propertyTypeName) + ) { + return false; + } + if (checkTypeClassWithObservedV2(propertyTypeIdentifier) || ARRAY_TYPES.includes(propertyTypeName)) { + isValidType = true; + } + } else if ( + arkts.isETSPrimitiveType(member) || + arkts.nodeType(member) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_STRING_LITERAL_TYPE || + arkts.nodeType(member) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_BROKEN_TYPE_NODE + ) { + return false; + } else if ( + arkts.nodeType(member) === arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_NULL_TYPE || + arkts.isETSUndefinedType(member) + ) { + continue; + } + } + return isValidType; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-require-decorator-regular.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-require-decorator-regular.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b5c5af290d77194421d77b9c3f9c2f757831bd3 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-require-decorator-regular.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 { BaseValidator } from '../base'; +import { StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { isPrivateClassProperty } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkRequireDecoratorRegular = performanceLog( + _checkRequireDecoratorRegular, + getPerfName([0, 0, 0, 0, 0], 'checkRequireDecoratorRegular') +); + +/** + * 校验规则:用于验证`@Require` 装饰器时需要遵循的具体约束和条件 + * 1.属性不能同时被 `private` 和 `@Require` 装饰器修饰。 + * + * 校验等级:error + */ +function _checkRequireDecoratorRegular( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + const requireDecorator = metadata.annotations?.[DecoratorNames.REQUIRE]; + // 属性不能同时被 `private` 和 `@Require` 装饰器修饰。 + if (!requireDecorator || !isPrivateClassProperty(node)) { + return; + } + const propertyName = metadata.name; + if (!propertyName) { + return; + } + this.report({ + node: requireDecorator, + level: LogType.WARN, + message: `Property '${propertyName}' can not be decorated with both 'Require' and private.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusable-component-in-V2.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusable-component-in-V2.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2412239d7e9feed25c6eb21e15b891b220c2943 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusable-component-in-V2.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 { BaseValidator } from '../base'; +import { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkReusableComponentInV2 = performanceLog( + _checkReusableComponentInV2, + getPerfName([0, 0, 0, 0, 0], 'checkReusableComponentInV2') +); + +/** + * 校验规则:用于验证使用 @ComponentV2 装饰的自定义组件中使用 @Reusable 装饰组件的可重用性 + * 1. @ComponentV2 装饰的自定义组件中不推荐使用 @Reusable 组件 + * + * 校验等级:warn + */ +function _checkReusableComponentInV2( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + // 如果非自定义组件调用,直接返回 + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + const fromComponentV2 = !!metadata.fromStructInfo?.annotationInfo?.hasComponentV2; + const fromReusableV2: boolean = !!metadata.fromStructInfo?.annotationInfo?.hasReusableV2; + const isReusableCall = !!metadata.structDeclInfo?.annotationInfo?.hasReusable; + + // @ComponentV2 装饰的自定义组件中不推荐使用 @Reusable 组件。(同时被@ReusableV2修饰时,由check-nested-reuse-component规则进行报错) + if (!fromComponentV2 || !isReusableCall || fromReusableV2) { + return; + } + const callExpression = arkts.unpackNonNullableNode(metadata.ptr!); + this.report({ + node: callExpression, + level: LogType.WARN, + message: `When a custom component is decorated with @ComponentV2 and contains a child component decorated with @Reusable, the child component will not create.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusableV2-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusableV2-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a2e7e105e3495eb4030a2a78210f2eb67a95cfc --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reusableV2-decorator.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 { BaseValidator } from '../base'; +import { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkReusableV2Decorator = performanceLog( + _checkReusableV2Decorator, + getPerfName([0, 0, 0, 0, 0], 'checkReusableV2Decorator') +); + +/** + * 校验规则:用于验证`@ReusableV2` 装饰器时需要遵循的具体约束和条件 + * 1. `@Reusable` 和 `@ReusableV2` 装饰器不能同时使用。 + * 2. `@ReusableV2` 只能用于使用了 `@ComponentV2` 的自定义组件。 + * + * 校验等级:error + */ +function _checkReusableV2Decorator( + this: BaseValidator, + struct: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + const hasComponentV2 = !!metadata.annotationInfo?.hasComponentV2; + const hasReusable = !!metadata.annotationInfo?.hasReusable; + const hasReusableV2 = !!metadata.annotationInfo?.hasReusableV2; + // `@Reusable` 和 `@ReusableV2` 装饰器不能同时使用。 + if (hasReusable && hasReusableV2) { + this.report({ + node: struct, + level: LogType.ERROR, + message: `The '@Reusable' and '@ReusableV2' annotations cannot be applied simultaneously.`, + }); + } + // `@ReusableV2` 只能用于使用了 `@ComponentV2` 的自定义组件。 + if (hasReusableV2 && !hasComponentV2) { + this.report({ + node: struct, + level: LogType.ERROR, + message: `@ReusableV2 is only applicable to custom components decorated by @ComponentV2.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reuse-attribute.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reuse-attribute.ts new file mode 100644 index 0000000000000000000000000000000000000000..3074331838b9354d70bbb9266e87e11f7ca009bf --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-reuse-attribute.ts @@ -0,0 +1,120 @@ +/* + * 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 { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkReuseAttribute = performanceLog( + _checkReuseAttribute, + getPerfName([0, 0, 0, 0, 0], 'checkReuseAttribute') +); + +const ReuseConstants = { + REUSE: 'reuse', + REUSE_ID: 'reuseId', +}; + +const INVALID_REUSE_USAGE = `The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2.`; +const INVALID_REUSE_ID_USAGE = `The reuseId attribute is not applicable to custom components decorated with both @ComponentV2 and @ReusableV2.`; + +const CHANGE_REUSE_TO_REUSE_ID = `Change reuse to reuseId`; +const CHANGE_REUSE_ID_TO_REUSE = `Change reuseId to reuse`; + +/** + * 校验规则:用于验证`reuse` 和`reuseId`属性时需要遵循的具体约束和条件 + * 1. `reuse` 属性只能用于同时使用了 `@ComponentV2` 和 `@ReusableV2` 装饰器的自定义组件。 + * 2. `reuseId` 属性不能用于同时使用了 `@ComponentV2` 和 `@ReusableV2` 装饰器的自定义组件。 + * + * 校验等级:error + */ +function _checkReuseAttribute(this: BaseValidator, node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // 如果非自定义组件调用,直接返回 + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + if ( + !arkts.isMemberExpression(node.callee) || + !node.callee.property || + !arkts.isCallExpression(node.callee.object) + ) { + return; + } + // Gets the reuse or reuseId attribute + const decoratedNode = node.callee.property; + if (!arkts.isIdentifier(decoratedNode)) { + return; + } + const structDefinition = arkts.unpackNonNullableNode(metadata.structDeclInfo.definitionPtr!); + if (!structDefinition || !structDefinition.parent || !arkts.isClassDeclaration(structDefinition.parent)) { + return; + } + // `reuse` 属性只能用于同时使用了 `@ComponentV2` 和 `@ReusableV2` 装饰器的自定义组件。 + if ( + decoratedNode.name === ReuseConstants.REUSE && + !( + metadata.structDeclInfo.annotationInfo?.hasComponentV2 && + metadata.structDeclInfo.annotationInfo?.hasReusableV2 + ) + ) { + reportInvalidReuseUsage.bind(this)(node, decoratedNode); + } + // `reuseId` 属性不能用于同时使用了 `@ComponentV2` 和 `@ReusableV2` 装饰器的自定义组件。 + if ( + decoratedNode.name === ReuseConstants.REUSE_ID && + metadata.structDeclInfo.annotationInfo?.hasComponentV2 && + metadata.structDeclInfo.annotationInfo?.hasReusableV2 + ) { + reportInvalidReuseIdUsage.bind(this)(node, decoratedNode); + } +} + +function reportInvalidReuseUsage( + this: BaseValidator, + node: arkts.AstNode, + decoratedNode: arkts.AstNode +): void { + this.report({ + node: node, + level: LogType.ERROR, + message: INVALID_REUSE_USAGE, + suggestion: createSuggestion( + ReuseConstants.REUSE_ID, + ...getPositionRangeFromNode(decoratedNode), + CHANGE_REUSE_TO_REUSE_ID + ), + }); +} + +function reportInvalidReuseIdUsage( + this: BaseValidator, + node: arkts.AstNode, + decoratedNode: arkts.AstNode +): void { + this.report({ + node: node, + level: LogType.ERROR, + message: INVALID_REUSE_ID_USAGE, + suggestion: createSuggestion( + ReuseConstants.REUSE, + ...getPositionRangeFromNode(decoratedNode), + CHANGE_REUSE_ID_TO_REUSE + ), + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-specific-component-children.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-specific-component-children.ts new file mode 100644 index 0000000000000000000000000000000000000000..eef337e5ad60716091326147bdb7f31d01d01bfc --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-specific-component-children.ts @@ -0,0 +1,110 @@ +/* + * 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 { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkSpecificComponentChildren = performanceLog( + _checkSpecificComponentChildren, + getPerfName([0, 0, 0, 0, 0], 'checkSpecificComponentChildren') +); + +const TOGGLE: string = 'Toggle'; +const TOGGLE_TYPE: string = 'ToggleType'; +const TYPE: string = 'type'; +const SINGLE_CHILD_COMPONENT: number = 1; +const ToggleType = { + CHECKBOX: 'Checkbox', + BUTTON: 'Button', +}; + +/** + * 校验规则:用于验证特定类型组件的子组件情况 + * 1. Toggle组件类型为`Checkbox`时,不可包含子组件 + * 2. Toggle组件类型为`Button`时,最多允许包含一个子组件 + * + * 校验等级:error + */ +function _checkSpecificComponentChildren( + this: BaseValidator, + node: arkts.CallExpression +): void { + const metadata = this.context ?? {}; + // If it's a custom component or the name isn't toggle, it returns + if (metadata.structDeclInfo || !metadata.fromStructInfo || metadata.declName !== TOGGLE) { + return; + } + const toggleType = getToggleType(node); + if (toggleType === '') { + return; + } + node.arguments.forEach((arg) => { + if ( + !arkts.isArrowFunctionExpression(arg) || + !arg.function.body || + !arkts.isBlockStatement(arg.function.body) + ) { + return; + } + // Toggle组件类型为`Checkbox`时,不可包含子组件 + if (toggleType === ToggleType.CHECKBOX && arg.function.body.statements.length > 0) { + this.report({ + node: node, + level: LogType.ERROR, + message: `When the component '${TOGGLE}' set '${TYPE}' as '${toggleType}', it can't have any child.`, + }); + } + // Toggle组件类型为`Button`时,最多允许包含一个子组件 + if (toggleType === ToggleType.BUTTON && arg.function.body.statements.length > SINGLE_CHILD_COMPONENT) { + this.report({ + node: node, + level: LogType.ERROR, + message: `When the component '${TOGGLE}' set '${TYPE}' as '${toggleType}', it can only have a single child component.`, + }); + } + }); +} + +function getToggleType(node: arkts.CallExpression): string { + let toggleType = ''; + node.arguments.some((member) => { + if (!arkts.isObjectExpression(member) || !member.properties) { + return false; + } + return member.properties.some((property) => { + if (!arkts.isProperty(property) || !property.value) { + return false; + } + // If the property name is not 'toggle type' + if ( + !arkts.isMemberExpression(property.value) || + !property.value.object || + !arkts.isIdentifier(property.value.object) || + property.value.object.name !== TOGGLE_TYPE + ) { + return false; + } + if (!property.value.property || !arkts.isIdentifier(property.value.property)) { + return false; + } + toggleType = property.value.property.name; + return true; + }); + }); + return toggleType; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-static-param-require.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-static-param-require.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff4af581d7f23734fbc9c2bb5cd57b13e2149d6b --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-static-param-require.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 { BaseValidator } from '../base'; +import { CallInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkStaticParamRequire = performanceLog( + _checkStaticParamRequire, + getPerfName([0, 0, 0, 0, 0], 'checkStaticParamRequire') +); + +/** + * 校验规则:用于校验通过组件构造函数初始化变量是否为静态变量。 + * 1. 向V1组件的`static`变量或V2组件带装饰器的`static`变量传参时,告警。 + * + * 校验等级:warn + */ +function _checkStaticParamRequire( + this: BaseValidator, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + // If a non-custom component is called and is not in the custom component, it returns directly + if (!metadata.structDeclInfo || !metadata.fromStructInfo) { + return; + } + const hasComponentV1 = metadata.structDeclInfo.annotationInfo?.hasComponent; + const hasComponentV2 = metadata.structDeclInfo.annotationInfo?.hasComponentV2; + if (!struct || !struct.parent || !arkts.isClassDeclaration(struct.parent)) { + return; + } + let staticClassProperty: string[] = []; + struct.parent?.definition?.body.forEach((property) => { + if (!arkts.isClassProperty(property) || !property.key || !arkts.isIdentifier(property.key)) { + return; + } + const propertyName = property.key.name; + if (propertyName === '' || !property.isStatic) { + return; + } + // Static properties in componentV1 or static properties with decorators in componentV2 need to be verified + if (hasComponentV1 || (hasComponentV2 && property.annotations.length > 0)) { + staticClassProperty.push(propertyName); + } + }); + metadata.structPropertyInfos?.forEach(([propertyPtr, propertyInfo]) => { + if (!propertyPtr || !propertyInfo || !propertyInfo.name || !staticClassProperty.includes(propertyInfo.name)) { + return; + } + // 向V1组件的`static`变量或V2组件带装饰器的`static`变量传参时,告警。 + const property = arkts.unpackNonNullableNode(propertyPtr); + this.report({ + node: property, + level: LogType.WARN, + message: `Static property '${propertyInfo.name}' can not be initialized through the component constructor.`, + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..583e544d6fac8c96de1a3573cbd8b2a0c0dc611a --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-decorator.ts @@ -0,0 +1,160 @@ +/* + * 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, StructMethodInfo, StructPropertyInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { checkIsNormalClassMethodFromInfo, checkIsStructMethodFromInfo } from '../../utils'; +import { getClassPropertyAnnotationNames } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkStructPropertyDecorator = performanceLog( + _checkStructPropertyDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkStructPropertyDecorator') +); + +const INVALID_STATIC_USAGE = `The static variable of struct cannot be used together with built-in annotations.`; + +const v1Decorators: string[] = [ + DecoratorNames.BUILDER_PARAM, + DecoratorNames.STATE, + DecoratorNames.PROP_REF, + DecoratorNames.LINK, + DecoratorNames.OBJECT_LINK, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.STORAGE_LINK, + DecoratorNames.WATCH, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.REQUIRE, +]; + +const v2Decorators: string[] = [ + DecoratorNames.PARAM, + DecoratorNames.ONCE, + DecoratorNames.EVENT, + DecoratorNames.PROVIDER, + DecoratorNames.CONSUMER, + DecoratorNames.MONITOR, + DecoratorNames.REQUIRE, +]; + +/** + * 校验规则:用于验证`struct` 结构体中的静态变量时需要遵循的具体约束和条件 + * 1. V1结构体(`struct`)中的静态变量不能与(V1)内置装饰器一起使用 + * 2. 结构体(`struct`)或类(`class`)中的静态变量或静态方法不能与(V2)内置装饰器一起使用 + * + * 校验等级:error + */ +function _checkStructPropertyDecorator(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkDecoratorInStructProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkDecoratorInMethodDefinition], +]); + +function checkDecoratorInStructProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const hasComponent = metadata.structInfo?.annotationInfo?.hasComponent; + const hasComponentV2 = metadata.structInfo?.annotationInfo?.hasComponentV2; + if (!node.isStatic || !arkts.isClassProperty(node)) { + return; + } + // V1结构体(`struct`)中的静态变量不能与(V1)内置装饰器一起使用 + if (hasComponent && hasPropertyDecorator(node, v1Decorators) && node.key) { + const propertyNameNode = node.key; + this.report({ + node: propertyNameNode, + level: LogType.ERROR, + message: INVALID_STATIC_USAGE, + }); + } + // 结构体(`struct`)或类(`class`)中的静态变量或静态方法不能与(V2)内置装饰器一起使用 + if (hasComponentV2 && hasPropertyDecorator(node, v2Decorators) && node.key) { + const propertyNameNode = node.key; + this.report({ + node: propertyNameNode, + level: LogType.ERROR, + message: INVALID_STATIC_USAGE, + }); + } +} + +function checkDecoratorInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructMethodFromInfo(metadata)) { + checkDecoratorInStructMethod.bind(this)(node); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkDecoratorInClassMethod.bind(this)(node); + } +} + +function checkDecoratorInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const hasComponentV2 = metadata.structInfo?.annotationInfo?.hasComponentV2; + if (!node.isStatic || !arkts.isMethodDefinition(node)) { + return; + } + // 结构体(`struct`)或类(`class`)中的静态变量或静态方法不能与(V2)内置装饰器一起使用 + if (hasComponentV2 && metadata.annotationInfo?.hasMonitor && node.id) { + const propertyNameNode = node.id; + this.report({ + node: propertyNameNode, + level: LogType.ERROR, + message: INVALID_STATIC_USAGE, + }); + } +} + +function checkDecoratorInClassMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + const hasObservedV2 = metadata.classInfo?.annotationInfo?.hasObservedV2; + if (!node.isStatic || !arkts.isMethodDefinition(node)) { + return; + } + // 结构体(`struct`)或类(`class`)中的静态变量或静态方法不能与(V2)内置装饰器一起使用 + if (hasObservedV2 && metadata.annotationInfo?.hasMonitor && node.id) { + const propertyNameNode = node.id; + this.report({ + node: propertyNameNode, + level: LogType.ERROR, + message: INVALID_STATIC_USAGE, + }); + } +} + +function hasPropertyDecorator(node: arkts.ClassProperty, decorators: string[]): boolean { + const annotationName = getClassPropertyAnnotationNames(node); + return decorators.some((decorator) => annotationName.includes(decorator)); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-optional.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-optional.ts new file mode 100644 index 0000000000000000000000000000000000000000..74bbb8143145946a8e36451d8cbcb8393fc13491 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-property-optional.ts @@ -0,0 +1,82 @@ +/* + * 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 { LogType, DecoratorNames } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkStructPropertyOptional = performanceLog( + _checkStructPropertyOptional, + getPerfName([0, 0, 0, 0, 0], 'checkStructPropertyOptional') +); + +function _checkStructPropertyOptional( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + const hasLink = !!metadata.annotationInfo?.hasLink; + const hasPropRef = !!metadata.annotationInfo?.hasPropRef; + const hasObjectLink = !!metadata.annotationInfo?.hasObjectLink; + if (!hasPropRef && !hasLink && !hasObjectLink) { + return; + } + + const modifiers = metadata.modifiers; + if (!modifiers) { + return; + } + + const isOptional = isClassPropertyOptional(modifiers); + if (!isOptional) { + return; + } + + const propertyName = metadata.name; + const propertyKey = node.key; + if (!propertyKey || !propertyName) { + return; + } + const propertyValue = node.value; + if (!propertyValue && hasPropRef) { + reportWarn.bind(this)(propertyKey, DecoratorNames.PROP_REF, propertyName); + } + if (hasLink) { + reportWarn.bind(this)(propertyKey, DecoratorNames.LINK, propertyName); + } + if (hasObjectLink) { + reportWarn.bind(this)(propertyKey, DecoratorNames.OBJECT_LINK, propertyName); + } +} + +function isClassPropertyOptional(modifiers: arkts.Es2pandaModifierFlags): boolean { + const flag = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; + return (modifiers & flag) === flag; +} + +function reportWarn( + this: BaseValidator, + node: arkts.Expression, + decoratorName: String, + propertyName: String +): void { + this.report({ + node: node, + level: LogType.WARN, + message: `The '${decoratorName}' property '${propertyName}' cannot be an optional parameter.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-variable-initialization.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-variable-initialization.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e173ac1aba98ba914cb5abd9b4399237d356306 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-struct-variable-initialization.ts @@ -0,0 +1,60 @@ +/* + * 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 { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkStructVariableInitialization = performanceLog( + _checkStructVariableInitialization, + getPerfName([0, 0, 0, 0, 0], 'checkStructVariableInitialization') +); + +/** + * 校验规则:用于验证装饰器修饰变量时需要遵循的本地初始化约束。 + * 1.`@Link`、和 `@ObjectLink` 修饰的变量不能在本地初始化。 + * 2.`@State`、`@StorageLink`、`@StoragePropRef`、`@LocalStorageLink`、`@StoragePropRef` 和 `@Provide` 修饰的变量必须在本地初始化(类型校验已拦截,本规则不做处理) + * + * 校验等级:error + */ +function _checkStructVariableInitialization( + this: BaseValidator, + classProperty: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo || !metadata.annotations) { + return; + } + let annotationName: string = ''; + let cannotInitAnnotation: arkts.AnnotationUsage | undefined = undefined; + for (const annotationKey in metadata.annotations) { + if (annotationKey !== DecoratorNames.LINK && annotationKey !== DecoratorNames.OBJECT_LINK) { + continue; + } + annotationName = annotationKey; + cannotInitAnnotation = metadata.annotations[annotationKey]; + break; + } + // `@Link`、和 `@ObjectLink` 修饰的变量不能在本地初始化。 + if (cannotInitAnnotation && classProperty.value && annotationName !== '') { + this.report({ + node: cannotInitAnnotation, + level: LogType.ERROR, + message: `The '@${annotationName}' property cannot be specified a default value.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-track-decorator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-track-decorator.ts new file mode 100644 index 0000000000000000000000000000000000000000..04c8731a91e875cd9d578449076f6a0a51ec3825 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-track-decorator.ts @@ -0,0 +1,201 @@ +/* + * 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 type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { + FunctionInfo, + GLobalPropertyInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + NormalInterfaceInfo, + StructMethodInfo, + StructPropertyInfo, +} from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromAnnotation } from '../../../../common/log-collector'; +import { + checkIsGlobalFunctionFromInfo, + checkIsNormalClassMethodFromInfo, + checkIsNormalClassPropertyFromInfo, + checkIsStructMethodFromInfo, + checkIsStructPropertyFromInfo, +} from '../../../../collectors/ui-collectors/utils'; +import { getAnnotationUsageByName } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkTrackDecorator = performanceLog( + _checkTrackDecorator, + getPerfName([0, 0, 0, 0, 0], 'checkTrackDecorator') +); + +const REMOVE_THE_ANNOTATION = `Remove the annotation`; + +/** + * 校验规则:用于验证`@track` 装饰器时需要遵循的具体约束和条件 + * 1.`@Track` 只能用于类的成员变量 + * 2.`@Track`不能用于被 `@ObservedV2` 装饰的类中 + * + * 校验等级:error + */ +function _checkTrackDecorator(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkTrackInClassProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkTrackInMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION, checkInvalidTrackInInterface], +]); + +function checkTrackInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructPropertyFromInfo(metadata)) { + checkInvalidTrackInStructProperty.bind(this)(node); + } else if (checkIsNormalClassPropertyFromInfo(metadata)) { + checkInvalidTrackInClassProperty.bind(this)(node); + } else { + checkInvalidTrackInGlobalProperty.bind(this)(node); + } +} + +function checkTrackInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructMethodFromInfo(metadata)) { + checkInvalidTrackInStructMethod.bind(this)(node); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkInvalidTrackInClassMethod.bind(this)(node); + } + if (checkIsGlobalFunctionFromInfo(metadata)) { + checkInvalidTrackInFunction.bind(this)(node); + } +} + +function checkInvalidTrackInStructProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Track` 只能用于类的成员变量 + if (metadata.ignoredAnnotationInfo?.hasTrack) { + const trackNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACK]!; + reportTrackOnClassMemberOnlyError.bind(this)(trackNode); + } +} + +function checkInvalidTrackInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Track`不能用于被 `@ObservedV2` 装饰的类中 + if (metadata.annotationInfo?.hasTrack && metadata.classInfo?.annotationInfo?.hasObservedV2) { + const trackNode = metadata.annotations?.[DecoratorNames.TRACK]!; + this.report({ + node: trackNode, + level: LogType.ERROR, + message: `'@Track' cannot be used with classes decorated by '@ObservedV2'. Use the '@Trace' annotation instead.`, + suggestion: createSuggestion(``, ...getPositionRangeFromAnnotation(trackNode), REMOVE_THE_ANNOTATION), + }); + } +} + +function checkInvalidTrackInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Track` 只能用于类的成员变量 + if (metadata.ignoredAnnotationInfo?.hasTrack) { + const trackNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACK]!; + reportTrackOnClassMemberOnlyError.bind(this)(trackNode); + } +} + +function checkInvalidTrackInFunction( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Track` 只能用于类的成员变量 + if (metadata.ignoredAnnotationInfo?.hasTrack) { + const trackNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACK]!; + reportTrackOnClassMemberOnlyError.bind(this)(trackNode); + } +} + +function checkInvalidTrackInClassMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // `@Track` 只能用于类的成员变量 + if (metadata.ignoredAnnotationInfo?.hasTrack) { + const trackNode = metadata.ignoredAnnotations?.[DecoratorNames.TRACK]!; + reportTrackOnClassMemberOnlyError.bind(this)(trackNode); + } +} + +function checkInvalidTrackInInterface( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + + if (!arkts.isTSInterfaceDeclaration(node)) { + return; + } + // `@Track` 只能用于类的成员变量 + const trackNode = getAnnotationUsageByName(node.annotations, DecoratorNames.TRACK); + if (trackNode) { + reportTrackOnClassMemberOnlyError.bind(this)(trackNode); + } +} + +function checkInvalidTrackInGlobalProperty( + this: BaseValidator, + node: T +): void { + // `@Track` 只能用于类的成员变量 + const trackDecoratorUsage = arkts.isClassProperty(node) + ? getAnnotationUsageByName(node.annotations, DecoratorNames.TRACK) + : undefined; + if (trackDecoratorUsage) { + reportTrackOnClassMemberOnlyError.bind(this)(trackDecoratorUsage); + } +} + +function reportTrackOnClassMemberOnlyError( + this: BaseValidator, + trackNode: arkts.AnnotationUsage +): void { + this.report({ + node: trackNode, + level: LogType.ERROR, + message: `The '@Track' annotation can decorate only member variables of a class.`, + suggestion: createSuggestion(``, ...getPositionRangeFromAnnotation(trackNode), REMOVE_THE_ANNOTATION), + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-ui-consistent.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-ui-consistent.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e565ed61c510660d3fd9f10711b0fad71973daa --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-ui-consistent.ts @@ -0,0 +1,219 @@ +/* + * 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 { checkIsCallFromInnerComponentOrExtendFromInfo, checkIsValidChainingDataSource } from '../utils'; +import { CallInfo } from '../../records'; +import { ChainingCallDataSource } from '../../chaining-call-data-source'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion, getPositionRangeFromNode } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; +import { MetaDataCollector } from '../../../../common/metadata-collector'; +import { ConsistentResourceMap } from '../../../../common/plugin-context'; + +export const checkUIConsistent = performanceLog(_checkUIConsistent, getPerfName([0, 0, 0, 0, 0], 'checkUIConsistent')); + +// The attributes of the VP unit must be used +const checkVpProperties = ['padding']; +// The property of VP/PX units must be used +const checkVpAndPxProperties = ['borderWidth', 'borderRadius', 'outlineWidth', 'outlineRadius']; +// The types of colors allowed +const colorUnionTypes = ['Color', 'Resource', 'string']; +// Resource color type tags +const resourceColorType = 'ResourceColor'; + +/** + * 校验规则:用于保持用户体验的一致性 + * 1. 使用consistentResourceInfo中的资源名称,替换`checkVpAndPxProperties`列表属性下以Vp或Px为单位的属性值 + * 2. 使用consistentResourceInfo中的资源名称,替换`checkVpProperties`列表属性下以Vp为单位的属性值 + * 3. 使用consistentResourceInfo中的资源名称,替换`color`属性下的`"#ffffffff"`格式的颜色值 + * + * 校验等级:warn + */ +function _checkUIConsistent(this: BaseValidator, node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // Check whether it is from inner components or from `@AnimatableExtend` + if (!checkIsCallFromInnerComponentOrExtendFromInfo(metadata)) { + return; + } + // Check whether it has chaining calls + if (!metadata.chainingCallInfos || metadata.chainingCallInfos.length === 0) { + return; + } + // Check whether chaining data is collected correctly + const chainingDataSource = ChainingCallDataSource.getInstance(); + if (!checkIsValidChainingDataSource(chainingDataSource, metadata)) { + return; + } + const consistentResourceMap = MetaDataCollector.getInstance().consistentResourceMap; + for (let idx = 0; idx < chainingDataSource.chainingCalls.length; idx++) { + const chainCall = chainingDataSource.chainingCalls.at(idx); + const chainingCallInfo = chainingDataSource.chainingCallInfos.at(idx); + if (!chainCall || !chainingCallInfo) { + return; + } + const callName = chainingCallInfo.callName!; + // Specific Attributes: Check the VP units + if (checkVpProperties.includes(callName)) { + checkVpUnit.bind(this)(chainCall, consistentResourceMap); + } + // Specific attributes: Check the VP and PX units + if (checkVpAndPxProperties.includes(callName)) { + checkVpAndPxUnit.bind(this)(chainCall, consistentResourceMap); + } + // Check the color parameter formatting + if (isColorProperty(callName)) { + checkColorParams.bind(this)(chainCall, consistentResourceMap); + } + } +} + +function isHexColor(color: string): boolean { + return /^(#([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8}))|(0x[0-9A-F]*)$/i.test(color); +} + +function isValidPx(size: string): boolean { + return /^\d+(\.\d+)?px$/.test(size); +} + +function isValidVp(size: string): boolean { + return /^\d+(\.\d+)?vp$/.test(size); +} + +function convertToDecimalPx(size: string): string { + // Remove meaningless 0, eg: '12.00px' + const formatSize = `${parseFloat(size)}${size.endsWith('px') ? 'px' : 'vp'}`; + // Regular expressions match numbers and units (e.g. px) + const regex = /^(\d+)(px|vp)$/; + const match = regex.exec(formatSize); + + if (match) { + // Get the numerical part and the unit part + const numberPart = match[1]; + const unitPart = match[2]; + + // Add a decimal point and a zero if there is no decimal point after the original number + const decimalSize = `${parseFloat(numberPart).toFixed(1)}${unitPart}`; + + return decimalSize; + } else { + // If there is no match, the original string is returned + return size; + } +} + +function isColorProperty(propertyName: string): boolean { + // If the attribute name contains 'ResourceColor', 'Color', 'Resource', 'string', it is mabe a color property + return propertyName.includes(resourceColorType) || colorUnionTypes.some((str) => propertyName.includes(str)); +} + +function checkVpUnit( + this: BaseValidator, + node: arkts.CallExpression, + resourceMap?: ConsistentResourceMap +): void { + if (!resourceMap) { + return; + } + // Gets the attribute value text and verifies the formatting + const sizeParams = node.arguments.filter((argNode) => arkts.isStringLiteral(argNode) && isValidVp(argNode.str)); + sizeParams.forEach((argNode) => { + const validVPStr = (argNode as arkts.StringLiteral).str; + const resources = resourceMap.get(validVPStr) ?? resourceMap.get(convertToDecimalPx(validVPStr)); + + // If consistent resource information doesn't exist, it won't be fixed + if (!resources || resources.length < 1) { + return; + } + const systemResource = `$r('sys.float.${resources[0].resourceName}')`; + this.report({ + node: argNode, + level: LogType.WARN, + message: `It is recommended that you use layered parameters for polymorphism development and resolution adaptation.`, + suggestion: createSuggestion( + systemResource, + ...getPositionRangeFromNode(argNode), + `change ${validVPStr} to ${systemResource}` + ), + }); + }); +} + +function checkVpAndPxUnit( + this: BaseValidator, + node: arkts.CallExpression, + resourceMap?: ConsistentResourceMap +): void { + if (!resourceMap) { + return; + } + // Gets the attribute value text and verifies the formatting + const sizeParams = node.arguments.filter( + (argNode) => arkts.isStringLiteral(argNode) && (isValidVp(argNode.str) || isValidPx(argNode.str)) + ); + sizeParams.forEach((argNode) => { + const validVPOrPxStr = (argNode as arkts.StringLiteral).str; + const resources = resourceMap.get(validVPOrPxStr) ?? resourceMap.get(convertToDecimalPx(validVPOrPxStr)); + + // If consistent resource information doesn't exist, it won't be fixed + if (!resources || resources.length < 1) { + return; + } + const systemResource = `$r('sys.float.${resources[0].resourceName}')`; + this.report({ + node: argNode, + level: LogType.WARN, + message: `It is recommended that you use layered parameters for polymorphism development and resolution adaptation.`, + suggestion: createSuggestion( + systemResource, + ...getPositionRangeFromNode(argNode), + `change ${validVPOrPxStr} to ${systemResource}` + ), + }); + }); +} + +function checkColorParams( + this: BaseValidator, + node: arkts.CallExpression, + resourceMap?: ConsistentResourceMap +): void { + if (!resourceMap) { + return; + } + // Gets the attribute value text and verifies the formatting + const colorParams = node.arguments.filter((argNode) => arkts.isStringLiteral(argNode) && isHexColor(argNode.str)); + colorParams.forEach((argNode) => { + const validColorStr = (argNode as arkts.StringLiteral).str; + const resources = resourceMap.get(validColorStr) ?? resourceMap.get(validColorStr.toUpperCase()); + + // If consistent resource information doesn't exist, it won't be fixed + if (!resources || resources.length < 1) { + return; + } + const systemResource = `$r('sys.color.${resources[0].resourceName}')`; + this.report({ + node: argNode, + level: LogType.WARN, + message: `It is recommended that you use layered parameters for easier color mode switching and theme color changing.`, + suggestion: createSuggestion( + systemResource, + ...getPositionRangeFromNode(argNode), + `change ${validColorStr} to ${systemResource}` + ), + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-build-in-struct.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-build-in-struct.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1a28da85335dde5d6964848935de4b67742780e --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-build-in-struct.ts @@ -0,0 +1,92 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { LogType } from '../../../../common/predefines'; +import { createSuggestion } from '../../../../common/log-collector'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +const BUILD_NAME = 'build'; + +export const checkValidateBuildInStruct = performanceLog( + _checkValidateBuildInStruct, + getPerfName([0, 0, 0, 0, 0], 'checkValidateBuildInStruct') +); + +function _checkValidateBuildInStruct( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + let hasBuild = false; + node.definition?.body.forEach((item) => { + if (!arkts.isMethodDefinition(item) || item.id?.name !== BUILD_NAME) { + return; + } + + if (!hasBuild) { + hasBuild = true; + } + + if (item.function.params.length !== 0) { + const firstParam = item.function.params[0]; + item.function.params.forEach((param) => { + this.report({ + node: param, + message: `The 'build' method can not have arguments.`, + level: LogType.ERROR, + suggestion: createSuggestion( + ``, + ...getStartAndEndPosition(item.function.params, firstParam), + `Remove the parameters of the build function` + ), + }); + }); + } + }); + + if (!hasBuild) { + const identifier = node.definition?.ident; + if (!identifier) { + return; + } + const position = arkts.createSourcePosition(node.endPosition.getIndex() - 1, node.endPosition.getLine()); + this.report({ + node: identifier, + message: `The struct '${identifier.name}' must have at least and at most one 'build' method.`, + level: LogType.ERROR, + suggestion: createSuggestion( + `build() {\n}\n`, + position, + position, + `Add a build function to the custom component` + ), + }); + } +} + +function getStartAndEndPosition( + params: readonly arkts.Expression[], + firstParam: arkts.Expression +): [arkts.SourcePosition, arkts.SourcePosition] { + let lastParam = firstParam; + params.forEach((param) => { + lastParam = param; + }); + + return [firstParam.startPosition, lastParam.endPosition]; +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-decorator-target.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-decorator-target.ts new file mode 100644 index 0000000000000000000000000000000000000000..20ee88a0d1f5178115eaa580d70f3b042cbf94b8 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-validate-decorator-target.ts @@ -0,0 +1,333 @@ +/* + * 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 type { ExtendedValidatorFunction, IntrinsicValidatorFunction } from '../safe-types'; +import { + CustomComponentInfo, + FunctionInfo, + GLobalPropertyInfo, + NormalClassInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + NormalInterfaceInfo, + StructMethodInfo, + StructPropertyInfo, +} from '../../records'; +import { DecoratorNames, LogType, StructDecoratorNames } from '../../../../common/predefines'; +import { + checkIsGlobalFunctionFromInfo, + checkIsNormalClassMethodFromInfo, + checkIsNormalClassPropertyFromInfo, + checkIsStructMethodFromInfo, + checkIsStructPropertyFromInfo, +} from '../../../../collectors/ui-collectors/utils'; +import { getAnnotationUsagesByName } from '../utils'; +import { checkIsCustomComponentFromInfo } from '../../../../collectors/ui-collectors/utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkValidateDecoratorTarget = performanceLog( + _checkValidateDecoratorTarget, + getPerfName([0, 0, 0, 0, 0], 'checkValidateDecoratorTarget') +); + +// Can only be used with decorators for struct +const structOnlyAnnotations = [ + StructDecoratorNames.REUSABLE, + StructDecoratorNames.REUSABLE_V2, + StructDecoratorNames.COMPONENT, + StructDecoratorNames.COMPONENT_V2, + StructDecoratorNames.ENTRY, + StructDecoratorNames.PREVIEW, + StructDecoratorNames.CUSTOMDIALOG, +]; + +// Can only be used with decorators for property +const propertyOnlyAnnotations = [ + DecoratorNames.STATE, + DecoratorNames.PROP_REF, + DecoratorNames.LINK, + DecoratorNames.PROVIDE, + DecoratorNames.CONSUME, + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.LOCAL_STORAGE_LINK, + DecoratorNames.WATCH, + DecoratorNames.REQUIRE, + DecoratorNames.OBJECT_LINK, +]; + +/** + * 校验规则:用于验证使用装饰器需遵循的具体约束和条件 + * 1. 组件装饰器只能作用于组件结构体。 + * 2. 属性装饰器只能作用于属性,不能用于方法等。 + * + * 校验等级:error + */ +function _checkValidateDecoratorTarget(this: BaseValidator, node: arkts.AstNode): void { + const nodeType = arkts.nodeType(node); + if (checkByType.has(nodeType)) { + checkByType.get(nodeType)!.bind(this)(node); + } +} + +const checkByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, checkRuleInClassProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, checkRuleInMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION, checkInvalidAnnotationInInterface], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, checkRuleInClassDeclaration], +]); + +function checkRuleInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructPropertyFromInfo(metadata)) { + checkInvalidAnnotationInStructProperty.bind(this)(node); + } else if (checkIsNormalClassPropertyFromInfo(metadata)) { + checkInvalidAnnotationInClassProperty.bind(this)(node); + } else { + checkInvalidAnnotationInGlobalProperty.bind(this)(node); + } +} + +function checkRuleInMethodDefinition( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsStructMethodFromInfo(metadata)) { + checkInvalidAnnotationInStructMethod.bind(this)(node); + } + if (checkIsNormalClassMethodFromInfo(metadata)) { + checkInvalidAnnotationInClassMethod.bind(this)(node); + } + if (checkIsGlobalFunctionFromInfo(metadata)) { + checkInvalidAnnotationInFunction.bind(this)(node); + } +} + +function checkRuleInClassDeclaration( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (checkIsCustomComponentFromInfo(metadata)) { + checkInvalidAnnotationInStruct.bind(this)(node); + } else { + checkInvalidAnnotationInClass.bind(this)(node); + } +} + +function checkInvalidAnnotationInStructProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations exist in the StructProperty + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInClassProperty( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the ClassProperty + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInStructMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the StructMethod + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInFunction( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the Function + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInClassMethod( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the ClassMethod + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInInterface( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + if (!arkts.isTSInterfaceDeclaration(node)) { + return; + } + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the Interface + const invalidStructAnnotation = getAnnotationUsagesByName(node.annotations, structOnlyAnnotations); + invalidStructAnnotation.forEach((annotationUsage) => { + if (!annotationUsage || !annotationUsage.expr || !arkts.isIdentifier(annotationUsage.expr)) { + return; + } + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotationUsage.expr.name); + }); + const invalidPropertyAnnotation = getAnnotationUsagesByName(node.annotations, propertyOnlyAnnotations); + invalidPropertyAnnotation.forEach((annotationUsage) => { + if (!annotationUsage || !annotationUsage.expr || !arkts.isIdentifier(annotationUsage.expr)) { + return; + } + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotationUsage.expr.name); + }); +} + +function checkInvalidAnnotationInGlobalProperty( + this: BaseValidator, + node: T +): void { + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the GlobalProperty + const metadata = this.context ?? {}; + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInStruct( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if propertyOnlyAnnotations exist in the Struct + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +function checkInvalidAnnotationInClass( + this: BaseValidator, + node: T +): void { + const metadata = this.context ?? {}; + // Error if structOnlyAnnotations or propertyOnlyAnnotations exist in the Class + structOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidStructAnnotation.bind(this)(annotationUsage, annotation); + } + }); + propertyOnlyAnnotations.forEach((annotation) => { + if (metadata.ignoredAnnotations?.[annotation]) { + const annotationUsage = metadata.ignoredAnnotations?.[annotation]!; + reportInvalidPropertyAnnotation.bind(this)(annotationUsage, annotation); + } + }); +} + +// 组件装饰器只能作用于组件结构体。 +function reportInvalidStructAnnotation( + this: BaseValidator, + errorNode: arkts.AnnotationUsage, + annotationName: string +): void { + this.report({ + node: errorNode, + level: LogType.ERROR, + message: `The '@${annotationName}' annotation can only be used with 'struct'.`, + }); +} + +// 属性装饰器只能作用于属性,不能用于方法等。 +function reportInvalidPropertyAnnotation( + this: BaseValidator, + errorNode: arkts.AnnotationUsage, + annotationName: string +): void { + this.report({ + node: errorNode, + level: LogType.ERROR, + message: `'@${annotationName}' can not decorate the method.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-variable-initialization-passing.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-variable-initialization-passing.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e887dbe2a3107aad7511fb558c5351f98f3a50f --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-variable-initialization-passing.ts @@ -0,0 +1,124 @@ +/* + * 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 { CallInfo, RecordBuilder, StructPropertyInfo, StructPropertyRecord } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkVariableInitializationPassing = performanceLog( + _checkVariableInitializationPassing, + getPerfName([0, 0, 0, 0, 0], 'checkVariableInitializationPassing') +); + +const notAllowInitDecorators: string[] = [ + DecoratorNames.STORAGE_LINK, + DecoratorNames.STORAGE_PROP_REF, + DecoratorNames.CONSUME, + DecoratorNames.LOCAL_STORAGE_LINK, +]; + +/** + * 校验规则:用于验证使用组件构造函数实现的参数初始化。 + * 1. `@Require`修饰的属性在组件构造时,必须赋值。 + * 2. 特定装饰器修饰的属性在组件构造时,禁止赋值 + * + * 校验等级:error + */ +function _checkVariableInitializationPassing( + this: BaseValidator, + node: arkts.CallExpression, + struct: arkts.ClassDefinition +): void { + const metadata = this.context ?? {}; + // 如果非自定义组件调用,直接返回 + if (!metadata.structDeclInfo || !metadata.fromStructInfo?.name) { + return; + } + const callName = metadata.callName!; + // 收集必须初始化装饰器修饰的属性 + const mustInitProperty: string[] = []; + struct.body.forEach((item) => { + if (!arkts.isClassProperty(item)) { + return; + } + const structPropertyRecord = RecordBuilder.build(StructPropertyRecord, item, { shouldIgnoreDecl: false }); + if (!structPropertyRecord.isCollected) { + structPropertyRecord.collect(item); + } + const propertyInfo = structPropertyRecord.toRecord(); + if (!propertyInfo) { + return; + } + if (checkPropertyMustInitFromInfo(propertyInfo)) { + const propertyName = propertyInfo.name!; + mustInitProperty.push(propertyName); + } + }); + metadata.structPropertyInfos?.forEach(([propertyPtr, propertyInfo]) => { + if (!propertyPtr || !propertyInfo || !propertyInfo.name) { + return; + } + // 如果已被初始化,移除出 mustInitProperty 数组 + if (mustInitProperty.includes(propertyInfo.name)) { + mustInitProperty.splice(mustInitProperty.indexOf(propertyInfo.name), 1); + } + // 检查被初始化的属性是否由禁止组件初始化装饰器修饰 + const cannotInitAnnotation = notAllowInitDecorators.find((annotation) => { + return propertyInfo.annotationInfo?.[`has${annotation}`]; + }); + if (!cannotInitAnnotation) { + return; + } + // 特定装饰器修饰的属性在组件构造时,禁止赋值 + const property = arkts.unpackNonNullableNode(propertyPtr); + this.report({ + node: property, + level: LogType.ERROR, + message: `The '@${cannotInitAnnotation}' property '${propertyInfo.name}' in the custom component '${callName}' cannot be initialized here (forbidden to specify).`, + }); + }); + // `@Require`修饰的属性在组件构造时,必须赋值。 + mustInitProperty.forEach((propertyName) => { + this.report({ + node: node, + level: LogType.ERROR, + message: `'@Require' decorated '${propertyName}' must be initialized through the component constructor.`, + }); + }); +} + +function checkPropertyMustInitFromInfo(metadata: StructPropertyInfo | undefined): boolean { + if (!!metadata?.annotationInfo?.hasRequire && Object.keys(metadata.annotationInfo).length === 1) { + return true; + } + if (!!metadata?.annotationInfo?.hasRequire && !!metadata?.annotationInfo?.hasState) { + return true; + } + if (!!metadata?.annotationInfo?.hasRequire && !!metadata?.annotationInfo?.hasProvide) { + return true; + } + if (!!metadata?.annotationInfo?.hasRequire && !!metadata?.annotationInfo?.hasPropRef) { + return true; + } + if (!!metadata?.annotationInfo?.hasRequire && !!metadata?.annotationInfo?.hasBuilderParam) { + return true; + } + if (!!metadata?.annotationInfo?.hasRequire && !!metadata?.annotationInfo?.hasParam) { + return true; + } + return false; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-function.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..54bedc429a164ec6eddee24741086aaa5caeef4a --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-function.ts @@ -0,0 +1,112 @@ +/* + * 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 { CustomComponentInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { createSuggestion } from '../../../../common/log-collector'; +import { getAnnotationUsageByName } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkWatchDecoratorFunction = performanceLog( + _checkWatchDecoratorFunction, + getPerfName([0, 0, 0, 0, 0], 'checkWatchDecoratorFunction') +); + +/** + * 校验规则:用于验证`@Watch` 装饰器的参数时需要遵循的具体约束和条件 + * 1. `@Watch` 必须指向已存在的方法名,即`@Watch` 装饰的参数必须是自定义组件中某个函数的回调方法 + * 2. `@Watch` 参数必须是字符串,不能是其它类型。(已有Type Error拦截,本规则不做校验) + * + * 校验等级:error + */ +function _checkWatchDecoratorFunction( + this: BaseValidator, + node: arkts.ClassDeclaration +): void { + const metadata = this.context ?? {}; + if (!node.definition) { + return; + } + // Get all struct method names + const methodNames = getMethodNames(node.definition); + node.definition.body.forEach((member) => { + if (!arkts.isClassProperty(member)) { + return; + } + const annotations = member.annotations; + if (!annotations) { + return; + } + const watchDecorator = getAnnotationUsageByName(annotations, DecoratorNames.WATCH); + // Determine whether it contains @watch decorators + validateWatchDecorator.bind(this)(member, methodNames, watchDecorator); + }); +} + +// Gets the names of all methods in the struct +function getMethodNames(definition: arkts.ClassDefinition): string[] { + const methodNames: string[] = []; + definition.body.forEach((member) => { + if (arkts.isMethodDefinition(member) && arkts.isIdentifier(member.id)) { + const methodName = member.id.name; + if (methodName !== '') { + methodNames.push(methodName); + } + } + }); + return methodNames; +} + +function validateWatchDecorator( + this: BaseValidator, + member: arkts.ClassProperty, + methodNames: string[], + watchDecorator: arkts.AnnotationUsage | undefined +): void { + member.annotations.forEach((annotation) => { + if (!annotation.expr || !arkts.isIdentifier(annotation.expr) || annotation.expr.name !== DecoratorNames.WATCH) { + return; + } + annotation.properties.forEach((element) => { + if (!arkts.isClassProperty(element)) { + return; + } + if (!element.value) { + return; + } + if (!arkts.isStringLiteral(element.value)) { + return; + } + const parameterName = element.value.str; + if (!watchDecorator || !parameterName || methodNames.includes(parameterName)) { + return; + } + // `@Watch` 必须指向已存在的方法名,即`@Watch` 装饰的参数必须是自定义组件中某个函数的回调方法 + this.report({ + node: watchDecorator, + level: LogType.ERROR, + message: `'@watch' cannot be used with '${parameterName}'. Apply it only to parameters that correspond to existing methods.`, + suggestion: createSuggestion( + `\n${parameterName}(){\n}`, + member.endPosition, + member.endPosition, + `Add a watch function to the custom component` + ), + }); + }); + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-regular.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-regular.ts new file mode 100644 index 0000000000000000000000000000000000000000..a39819b75936e50fa3d264872175b31032e58b07 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-watch-decorator-regular.ts @@ -0,0 +1,50 @@ +/* + * 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 { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkWatchDecoratorRegular = performanceLog( + _checkWatchDecoratorRegular, + getPerfName([0, 0, 0, 0, 0], 'checkWatchDecoratorRegular') +); + +/** + * 校验规则:用于验证`@Watch` 装饰器时需要遵循的具体约束和条件 + * 1. 不能单独使用 `@Watch` 装饰器,需要和其他装饰器配合使用。 + * + * 校验等级:error + */ +function _checkWatchDecoratorRegular( + this: BaseValidator, + node: arkts.ClassProperty +): void { + const metadata = this.context ?? {}; + const hasWatch = metadata.annotationInfo?.hasWatch; + const annotationCount = node.annotations.length; + + // 不能单独使用 `@Watch` 装饰器,需要和其他装饰器配合使用 + if (hasWatch && annotationCount === 1) { + const watchDecorator = metadata.annotations?.[DecoratorNames.WATCH]!; + this.report({ + node: watchDecorator, + level: LogType.ERROR, + message: `Regular variable '${metadata.name}' can not be decorated with '@Watch'.`, + }); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-wrap-builder.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-wrap-builder.ts new file mode 100644 index 0000000000000000000000000000000000000000..594522d54d8f070faf94a82170c7436d8b1008cf --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/check-wrap-builder.ts @@ -0,0 +1,69 @@ +/* + * 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 { CallInfo } from '../../records'; +import { DecoratorNames, LogType } from '../../../../common/predefines'; +import { getAnnotationUsageByName } from '../utils'; +import { getPerfName, performanceLog } from '../../../../common/debug'; + +export const checkWrapBuilder = performanceLog(_checkWrapBuilder, getPerfName([0, 0, 0, 0, 0], 'checkWrapBuilder')); + +const WRAP_BUILDER: string = 'wrapBuilder'; + +/** + * 校验规则:用于验证wrapBuilder函数的使用。 + * 1. wrapBuilder的参数必须为`@Builder`修饰的function + * + * 校验等级:error + */ +function _checkWrapBuilder(this: BaseValidator, node: arkts.CallExpression): void { + const metadata = this.context ?? {}; + // If it is a custom component or the name is not wrapBuilder, it returns + if (metadata.structDeclInfo || metadata.declName !== WRAP_BUILDER) { + return; + } + // If the parameter length is not 1, the report type is incorrect + if (node.arguments.length !== 1) { + return; + } + const funcIdentifier = node.arguments[0]; + // When node.arguments[0] is the identifier, it means that the parameter is a global function + if (arkts.isIdentifier(node.arguments[0])) { + let decl: arkts.AstNode | undefined; + if ( + !(decl = arkts.getPeerIdentifierDecl(funcIdentifier.peer)) || + !arkts.isMethodDefinition(decl) || + !arkts.isFunctionExpression(decl) || + !arkts.isScriptFunction(decl.function) + // !arkts.isScriptFunction(decl.funcExpr.scriptFunction) + ) { + return; + } + // If the parameter is a Builder decorated method, no error will be reported + const funcAnnotations = decl.function.annotations; + const builderDecorator = getAnnotationUsageByName(funcAnnotations, DecoratorNames.BUILDER); + if (builderDecorator) { + return; + } + } + // wrapBuilder的参数必须为`@Builder`修饰的function + this.report({ + node: funcIdentifier, + level: LogType.ERROR, + message: `The wrapBuilder\'s parameter should be @Builder function.`, + }); +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a6f0207d244719f5504601c2fe7fb73ac7f56094 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/rules/index.ts @@ -0,0 +1,65 @@ +/* + * 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-attribute-no-invoke'; +export * from './check-build-root-node'; +export * from './check-builder-param'; +export * from './check-component-componentV2-init'; +export * from './check-component-componentV2-mix-use'; +export * from './check-componentV2-mix'; +export * from './check-componentV2-state-usage'; +export * from './check-computed-decorator'; +export * from './check-construct-parameter-literal'; +export * from './check-construct-parameter'; +export * from './check-construct-private-parameter'; +export * from './check-consumer-provider-decorator'; +export * from './check-custom-dialog-missing-controller'; +export * from './check-decorated-property-type'; +export * from './check-entry-localstorage'; +export * from './check-entry-struct-no-export'; +export * from './check-old-new-decorator-mix-use'; +export * from './check-once-decorator'; +export * from './check-main-pages-entry-check'; +export * from './check-monitor-decorator'; +export * from './check-nested-relationship'; +export * from './check-nested-reuse-component'; +export * from './check-no-child-in-button'; +export * from './check-no-duplicate-id'; +export * from './check-no-duplicate-preview'; +export * from './check-no-prop-link-objectlink-in-entry'; +export * from './check-no-same-as-built-in-attribute'; +export * from './check-observed-heritage-compatible'; +export * from './check-observed-observedV2'; +export * from './check-observedV2-trace-usage-validation'; +export * from './check-one-decorator-on-function-method'; +export * from './check-property-modifiers'; +export * from './check-property-type'; +export * from './check-require-decorator-regular'; +export * from './check-reusable-component-in-V2'; +export * from './check-reusableV2-decorator'; +export * from './check-reuse-attribute'; +export * from './check-specific-component-children'; +export * from './check-static-param-require'; +export * from './check-struct-property-decorator'; +export * from './check-struct-property-optional'; +export * from './check-struct-variable-initialization'; +export * from './check-track-decorator'; +export * from './check-ui-consistent'; +export * from './check-validate-build-in-struct'; +export * from './check-validate-decorator-target'; +export * from './check-variable-initialization-passing'; +export * from './check-watch-decorator-function'; +export * from './check-watch-decorator-regular'; +export * from './check-wrap-builder'; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/safe-types.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/safe-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5583c4e15fab34415f764714eb8eb497dd2b553 --- /dev/null +++ b/ui2abc/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; diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ebbbccc360eb4c894d84a8903515c96e7913f69 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-method-validator.ts @@ -0,0 +1,52 @@ +/* + * 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 { + checkBuildRootNode, + checkComponentV2StateUsage, + checkComputedDecorator, + checkConsumerProviderDecorator, + checkMonitorDecorator, + checkObservedV2TraceUsageValidation, + checkOnceDecorator, + checkStructPropertyDecorator, + checkTrackDecorator, + checkValidateDecoratorTarget, +} 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); + checkOnceDecorator.bind(this)(node); + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkStructPropertyDecorator.bind(this)(node); + checkMonitorDecorator.bind(this)(node); + checkBuildRootNode.bind(this)(node); + + const struct = arkts.unpackNode(metadata.structInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, struct); + checkValidateDecoratorTarget.bind(this)(node); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..8371c79f508c1e8916ae8496dfd6e4014b8181d8 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-property-validator.ts @@ -0,0 +1,72 @@ +/* + * 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 { + checkComponentComponentV2MixUse, + checkComponentV2StateUsage, + checkComputedDecorator, + checkConsumerProviderDecorator, + checkEntryLocalStorage, + checkDecoratedPropertyType, + checkOldNewDecoratorMixUse, + checkOnceDecorator, + checkStructVariableInitialization, + checkPropertyType, + checkStructPropertyDecorator, + checkPropertyModifiers, + checkRequireDecoratorRegular, + checkTrackDecorator, + checkObservedV2TraceUsageValidation, + checkNoPropLinkObjectlinkInEntry, + checkMonitorDecorator, + checkValidateDecoratorTarget, + checkWatchDecoratorRegular, + checkStructPropertyOptional, +} from './rules'; + +export class StructPropertyValidator extends BaseValidator { + reportIfViolated(node: arkts.ClassProperty): void { + const metadata = this.context ?? {}; + if (!metadata.structInfo?.definitionPtr) { + return; + } + + checkComponentComponentV2MixUse.bind(this)(node); + checkComponentV2StateUsage.bind(this)(node); + checkConsumerProviderDecorator.bind(this)(node); + checkEntryLocalStorage.bind(this)(node); + checkDecoratedPropertyType.bind(this)(node); + checkOldNewDecoratorMixUse.bind(this)(node); + checkOnceDecorator.bind(this)(node); + checkStructVariableInitialization.bind(this)(node); + checkPropertyType.bind(this)(node); + checkStructPropertyDecorator.bind(this)(node); + checkPropertyModifiers.bind(this)(node); + checkRequireDecoratorRegular.bind(this)(node); + checkTrackDecorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkNoPropLinkObjectlinkInEntry.bind(this)(node); + checkMonitorDecorator.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkWatchDecoratorRegular.bind(this)(node); + checkStructPropertyOptional.bind(this)(node); + + const struct = arkts.unpackNode(metadata.structInfo.definitionPtr); + checkComputedDecorator.bind(this)(node, struct); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-validator.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-validator.ts new file mode 100644 index 0000000000000000000000000000000000000000..dcae1a260cdc9e044a921d68854cc927aea62f23 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/struct-validator.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 { CustomComponentInfo } from '../records'; +import { + checkComponentV2Mix, + checkCustomDialogMissingController, + checkEntryStructNoExport, + checkMainPagesEntry, + checkNoDuplicatePreview, + checkNoSameAsBuiltInAttribute, + checkObservedV2TraceUsageValidation, + checkReusableV2Decorator, + checkValidateDecoratorTarget, + checkWatchDecoratorFunction, + resetMainPagesEntry, + resetNoDuplicatePreview, + checkValidateBuildInStruct +} from './rules'; + +export class StructValidator extends BaseValidator { + reset(): void { + super.reset(); + resetMainPagesEntry.bind(this)(); + resetNoDuplicatePreview.bind(this)(); + } + + reportIfViolated(node: arkts.ClassDeclaration): void { + checkReusableV2Decorator.bind(this)(node); + checkObservedV2TraceUsageValidation.bind(this)(node); + checkComponentV2Mix.bind(this)(node); + checkCustomDialogMissingController.bind(this)(node); + checkNoSameAsBuiltInAttribute.bind(this)(node); + checkValidateDecoratorTarget.bind(this)(node); + checkWatchDecoratorFunction.bind(this)(node); + checkEntryStructNoExport.bind(this)(node); + checkMainPagesEntry.bind(this)(node); + checkNoDuplicatePreview.bind(this)(node); + checkValidateBuildInStruct.bind(this)(node); + } +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/utils.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..9becf56b79688e7e585435295a51a375718975af --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/utils.ts @@ -0,0 +1,209 @@ +/* + * 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, isDeclFromArkUI } from '../utils'; +import { BuiltInNames } from '../../../common/predefines'; +import { ChainingCallDataSource } from '../chaining-call-data-source'; +import { CallInfo } from '../records'; + +export const TypeFlags = { + Boolean: 'boolean', + String: 'string', + Number: 'number', + Enum: 'enum', + Null: 'null', + Undefined: 'undefined', + Object: 'object', + Array: 'array', + Function: 'function', + Symbol: 'symbol', + BigInt: 'bigint', + Unknown: 'unknown', + Any: 'any', + Never: 'never', + Void: 'void', + This: 'this', + TypeParameter: 'typeParameter', + Literal: 'literal', + Union: 'union', +}; + +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; +} + +export function isPublicClassProperty(property: arkts.ClassProperty): boolean { + return arkts.hasModifierFlag(property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC); +} + +export function isPrivateClassProperty(property: arkts.ClassProperty): boolean { + return arkts.hasModifierFlag(property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE); +} + +export function isProtectedClassProperty(property: arkts.ClassProperty): boolean { + return arkts.hasModifierFlag(property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED); +} + +export function isClassDeclaration(node: arkts.AstNode): node is arkts.ClassDeclaration { + return ( + arkts.isClassDeclaration(node) && !!node.definition && !node.definition.isFromStruct + ); +} + +export function isInEtsGlobalClassDeclaration(node: arkts.AstNode): boolean { + while (node) { + if (isClassDeclaration(node)) { + if (node.definition?.ident?.name === BuiltInNames.ETS_GLOBAL_CLASS) { + return true; + } else { + return false; + } + } + if (!node.parent) { + return false; + } + node = node.parent; + } + return false; +} + +//Global method +export function isFunctionDeclaration(node: arkts.AstNode): node is arkts.MethodDefinition { + if (!arkts.isMethodDefinition(node) || !node.isStatic || !node.function.id) { + return false; + } + const methodName = node.function.id.name; + return ( + methodName !== BuiltInNames.GLOBAL_INIT_METHOD && + methodName !== BuiltInNames.GLOBAL_MAIN_METHOD && + isInEtsGlobalClassDeclaration(node) + ); +} + +//Global variables +export function isVariableDeclaration(node: arkts.AstNode): node is arkts.ClassProperty { + return arkts.isClassProperty(node) && isInEtsGlobalClassDeclaration(node); +} + +export function getAnnotationUsagesByName( + annotations: readonly arkts.AnnotationUsage[], + annotationNames: string[] +): Array { + return annotationNames.map((annotationName) => getAnnotationUsageByName(annotations, annotationName)); +} + +export function getAnnotationUsageByName( + annotations: readonly arkts.AnnotationUsage[], + annotationName: string +): arkts.AnnotationUsage | undefined { + return annotations.find((annotation: arkts.AnnotationUsage): boolean => { + if (!annotation.expr || !arkts.isIdentifier(annotation.expr) || annotation.expr.name !== annotationName) { + return false; + } + const annotationDeclaration = arkts.getPeerIdentifierDecl(annotation.expr.peer); + if (!annotationDeclaration || !isDeclFromArkUI(annotationDeclaration)) { + return false; + } + return true; + }); +} + +export function getAnnotationUsage( + annotations: readonly arkts.AnnotationUsage[], + annotationName: string +): arkts.AnnotationUsage | undefined { + return annotations.find( + (annotation) => + annotation.expr && arkts.isIdentifier(annotation.expr) && annotation.expr.name === annotationName + ); +} + +export function getIdentifierName(node: arkts.AstNode): string { + if (!arkts.isIdentifier(node)) { + return ''; + } + return node.name; +} + +export function getClassPropertyAnnotationNames(property: arkts.ClassProperty): string[] { + return property.annotations + .map((annotation) => getAnnotationName(annotation)) + .filter((item): item is string => item !== undefined); +} + +export function isBuiltInDeclaration(node: arkts.Identifier): boolean { + const declaration = arkts.getPeerIdentifierDecl(node.peer); + if (!declaration || !isDeclFromArkUI(declaration)) { + return false; + } + return true; +} + +export function getCurrentFilePath(node: arkts.AstNode): string | undefined { + const program = arkts.getProgramFromAstNode(node); + return program?.absoluteName; +} + +export function checkIsValidChainingDataSource(dataSource: ChainingCallDataSource, thisCallInfo: CallInfo): boolean { + if (!thisCallInfo.rootCallInfo?.ptr || !dataSource.rootCallInfo?.callRecord.callPtr) { + return false; + } + if (thisCallInfo.rootCallInfo.ptr !== dataSource.rootCallInfo.callRecord.callPtr) { + return false; + } + if (!thisCallInfo.chainingCallInfos || !dataSource.chainingCallInfos) { + return false; + } + return thisCallInfo.chainingCallInfos.length === dataSource.chainingCallInfos.length; +} + +export function checkIsCallFromInnerComponentOrExtendFromInfo(metadata: CallInfo): boolean { + const rootCallInfo = metadata.rootCallInfo; + if (!rootCallInfo) { + return false; + } + if (!!rootCallInfo.annotationInfo?.hasComponentBuilder) { + return !metadata.rootCallInfo?.structDeclInfo; + } + if (!!rootCallInfo.annotationInfo?.hasAnimatableExtend) { + return true; + } + if (!!rootCallInfo.annotationInfo?.hasBuilder) { + return true; + } + return false; +} diff --git a/ui2abc/arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/validator-builder.ts new file mode 100644 index 0000000000000000000000000000000000000000..754d56533c14b4cc82aab5e0b6586900bd222532 --- /dev/null +++ b/ui2abc/arkui-plugins/collectors/ui-collectors/validators/validator-builder.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 { Validator } from './base'; +import { clearValidatorCache, getOrPut } from './cache'; + +export class ValidatorBuilder { + static shouldSkip: boolean = false; + + static build(Validator: { name: string; new (): Validator }): Validator { + return getOrPut(Validator.name, () => new Validator(), this.shouldSkip); + } + + static reset(): void { + this.shouldSkip = false; + clearValidatorCache(); + } +} diff --git a/ui2abc/arkui-plugins/common/abstract-visitor.ts b/ui2abc/arkui-plugins/common/abstract-visitor.ts index e0a5f1a0dd4fabb4650ba77c2ac771ce0802af15..a609577bb9e5e5393d567311e59179c7571dc76b 100644 --- a/ui2abc/arkui-plugins/common/abstract-visitor.ts +++ b/ui2abc/arkui-plugins/common/abstract-visitor.ts @@ -21,68 +21,43 @@ export interface VisitorOptions { program?: arkts.Program; } -export abstract class AbstractVisitor extends arkts.AbstractVisitor implements VisitorOptions { +export abstract class AbstractVisitor implements VisitorOptions { public isExternal: boolean; public externalSourceName?: string; public program?: arkts.Program; constructor(options?: VisitorOptions) { - super() this.isExternal = options?.isExternal ?? false; this.externalSourceName = options?.externalSourceName; this.program = options?.program; } - process(node: arkts.AstNode, options?: any): arkts.AstNode { - let result = super.process(node, options) - return result + + indentation = 0; + + withIndentation(exec: () => T) { + this.indentation++; + const result = exec(); + this.indentation--; + return result; } -} -export abstract class FilteringReadonlyVisitor extends AbstractVisitor { - types: arkts.Es2pandaAstNodeType[] - processOverlaps: boolean - enable: boolean - constructor(types: arkts.Es2pandaAstNodeType[], enable: boolean, processOverlaps: boolean = false, options?: VisitorOptions) { - super() - this.types = types - this.processOverlaps = processOverlaps - this.enable = enable + getOptions(): VisitorOptions { + return { + isExternal: this.isExternal, + externalSourceName: this.externalSourceName, + program: this.program, + }; } - private checkParents(node: arkts.AstNode, nodes: Set): boolean { - let current = node.parent - while (current) { - if (nodes.has(current)) return true - current = current.parent - } - return false + abstract visitor(node: arkts.AstNode): arkts.AstNode; + + init(): void {} + + reset(): void { + this.indentation = 0; } - process(node: arkts.AstNode, options?: any): arkts.AstNode { - if (this.enable) { - const start = Date.now() - if (this.processOverlaps) { - const nodes = new Set() - arkts.filterNodesByTypes(node, this.types) - .forEach(it => nodes.add(it)) - nodes.forEach(node => { - if (this.checkParents(node, nodes)) { - nodes.delete(node) - } - }) - nodes.forEach(it => { - this.visitor(it, options) - }) - } else { - arkts.filterNodesByTypes(node, this.types) - .forEach(it => { - const result = this.visitor(it, options) - }) - } - console.log(`Filtering${this.enable ? "" : '(disabled)'}: ${this.constructor.name} took ${Date.now() - start}ms`) - } else { - super.process(node, options) - } - return node + visitEachChild(node: arkts.AstNode): arkts.AstNode { + return arkts.visitEachChild(node, (it) => this.visitor(it)); } -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/common/arkts-utils.ts b/ui2abc/arkui-plugins/common/arkts-utils.ts index 04faad94d7e36c7743a2d532fdb54960a8587898..a7ebe2eacd238855088eed7e723c947da8285fe0 100644 --- a/ui2abc/arkui-plugins/common/arkts-utils.ts +++ b/ui2abc/arkui-plugins/common/arkts-utils.ts @@ -14,13 +14,46 @@ */ import * as arkts from '@koalaui/libarkts'; -import { DeclarationCollector } from './declaration-collector'; -import { ARKUI_IMPORT_PREFIX_NAMES, DecoratorNames, StructDecoratorNames } from './predefines'; import * as fs from 'fs'; +import * as path from 'path'; +import { DeclarationCollector } from './declaration-collector'; +import { + APPLICATION_MAIN_BASE_RESOURCE_PATH, + APPLICATION_MAIN_ETS_PATH, + ARKUI_IMPORT_PREFIX_NAMES, + DecoratorNames, + LIB_UI_COMPONENTS_PATH, + PREVIEWER_RESOURCE_SKIP_PREFIX_NAMES, + PREVIEWER_RESOURCE_PATH, +} from './predefines'; +import { + ApplicationMainPages, + ApplicationModuleConfig, + ComponentJson, + ConsistentResourceInfo, + ConsistentResourceMap, + ProjectConfig, + UIComponents, +} from './plugin-context'; + +export function expectNameInTypeReference(node: arkts.TypeNode | undefined): arkts.Identifier | undefined { + if (!node || !arkts.isETSTypeReference(node)) { + return undefined; + } + const part = node.part; + if (!part || !arkts.isETSTypeReferencePart(part)) { + return undefined; + } + const nameNode = part.name; + if (!nameNode || !arkts.isIdentifier(nameNode)) { + return undefined; + } + return nameNode; +} /** * Visit base method and all its overloads with visitor. - * + * * @param method base method AstNode * @param visitor rewrite visitor for each method AstNode * @returns new base method AstNode with new overloads @@ -63,18 +96,18 @@ export function isAnnotation(node: arkts.AnnotationUsage, annoName: string) { export function isDecoratorAnnotation( anno: arkts.AnnotationUsage, - decoratorName: DecoratorNames | StructDecoratorNames, + decoratorName: DecoratorNames, ignoreDecl?: boolean ): boolean { if (!(!!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName)) { return false; } if (!ignoreDecl) { - const decl = arkts.getDecl(anno.expr); + const decl = arkts.getPeerIdentifierDecl(anno.expr.peer); 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; } @@ -109,7 +142,7 @@ export function backingField(originalName: string): string { } export function filterDefined(value: (T | undefined)[]): T[] { - return value.filter((it: T | undefined): it is T => (it !== undefined && it !== null)); + return value.filter((it: T | undefined): it is T => it != undefined); } export function collect(...value: (ReadonlyArray | T | undefined)[]): T[] { @@ -195,3 +228,165 @@ export function readFirstLineSync(filePath: string): string | null { return firstLine; } + +/** + * find the last property element in array. + * + * @param arr array. + * @param callback selected condition. + */ +export function findLastPropertyElement(arr: Array, callback: (item: T) => boolean): T | undefined { + if (arr.length <= 0) { + return undefined; + } + for (let index = arr.length - 1; index >= 0; index--) { + const item: T = arr[index]; + if (callback(item)) { + return item; + } + } + return undefined; +} + +export function readJSON(path: string): T | null { + if (!fs.existsSync(path)) { + return null; + } + const content = fs.readFileSync(path).toString(); + if (!content) { + return null; + } + return JSON.parse(content) as T; +} + +export function getUIComponents(): UIComponents | undefined { + let builtInAttributes: string[] = []; + let containerComponents: string[] = []; + let atomicComponents: string[] = []; + let singleChildComponents: string[] = []; + let validParentComponent: Map = new Map(); + let validChildComponent: Map = new Map(); + + if (!fs.existsSync(LIB_UI_COMPONENTS_PATH)) { + return undefined; + } + // Read all files in the directory + const files = fs.readdirSync(LIB_UI_COMPONENTS_PATH); + + files.forEach((file) => { + if (path.extname(file) === '.json') { + const filePath = path.join(LIB_UI_COMPONENTS_PATH, file); + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const componentJson: ComponentJson = JSON.parse(fileContent); + // Record the container component name + if ((!componentJson.atomic || componentJson.atomic !== true) && componentJson.name) { + containerComponents.push(componentJson.name); + } + // Record the atomic component name + if (componentJson.atomic && componentJson.atomic === true && componentJson.name) { + atomicComponents.push(componentJson.name); + } + // Record the name of a single subComponent component name + if (componentJson.single && componentJson.single === true && componentJson.name) { + singleChildComponents.push(componentJson.name); + } + // Record a valid parent component name + if (componentJson.parents && componentJson.name) { + validParentComponent.set(componentJson.name, componentJson.parents); + } + // Record a valid children component name + if (componentJson.children && componentJson.name) { + validChildComponent.set(componentJson.name, componentJson.children); + } + // Document all built-in attributes + componentJson.attrs + ?.filter((attr) => !builtInAttributes.includes(attr)) + .forEach((attr) => builtInAttributes.push(attr)); + } + }); + return { + builtInAttributes, + containerComponents, + atomicComponents, + singleChildComponents, + validParentComponent, + validChildComponent, + }; +} + +export function getMainPages(projectConfig?: ProjectConfig): string[] { + if (!projectConfig) { + return []; + } + + const { moduleRootPath, aceModuleJsonPath } = projectConfig; + if (!aceModuleJsonPath) { + return []; + } + const moduleConfig = readJSON(aceModuleJsonPath); + if (!moduleConfig) { + return []; + } + if (!moduleConfig.module || !moduleConfig.module.pages) { + return []; + } + const pagesPath = moduleConfig.module.pages; + const matcher = /\$(?[_A-Za-z]+):(?[_A-Za-z]+)/.exec(pagesPath); + if (matcher && matcher.groups) { + const { directory, filename } = matcher.groups; + const mainPagesPath = path.resolve( + moduleRootPath, + APPLICATION_MAIN_BASE_RESOURCE_PATH, + directory, + `${filename}.json` + ); + const mainPages = readJSON(mainPagesPath); + if (!mainPages) { + return []; + } + if (!mainPages.src || !Array.isArray(mainPages.src)) { + return []; + } + return mainPages.src.map((page) => path.resolve(moduleRootPath, APPLICATION_MAIN_ETS_PATH, `${page}.ets`)); + } else { + return []; + } +} + +export function getConsistentResourceMap(): ConsistentResourceMap { + const resultMap = new Map(); + let resourceText: string = ''; + try { + // The contents of the file are read synchronously + resourceText = fs.readFileSync(PREVIEWER_RESOURCE_PATH, 'utf-8'); + } catch (error: unknown) { + return resultMap; + } + // Split text by line + const lines = resourceText.split('\n'); + for (const line of lines) { + // Skip blank lines + if (!line.trim()) { + continue; + } + const match = line.match(/id:(\d+),\s*'([^']+)'\s*'([^']+)'/); + if (match && match.length === 4) { + const id = match[1]; + const value = match[2]; + const resourceName = match[3]; + if (matchPrefix(PREVIEWER_RESOURCE_SKIP_PREFIX_NAMES, resourceName)) { + continue; + } + let entries = resultMap.get(value); + if (!entries) { + entries = []; + resultMap.set(value, entries); + } + entries.push({ + id: id, + resourceName: resourceName, + }); + } + } + return resultMap; +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/common/cache/astNodeRevisitCache.ts b/ui2abc/arkui-plugins/common/cache/astNodeRevisitCache.ts index d2e57ea6efde5491e28e260f46aafaf35b0a568c..d60308d0b3f131c95b4fb50244bbb9566769add9 100644 --- a/ui2abc/arkui-plugins/common/cache/astNodeRevisitCache.ts +++ b/ui2abc/arkui-plugins/common/cache/astNodeRevisitCache.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2025 Huawei Device Co., Ltd. + * 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 @@ -14,31 +14,38 @@ */ import * as arkts from '@koalaui/libarkts'; +import { AstNodePointer } from '../safe-types'; export class AstNodeRevisitCache { - private static instance?: AstNodeRevisitCache; + private _visitedTypePeers: Set; + private static instance: AstNodeRevisitCache | null = null; + + private constructor() { + this._visitedTypePeers = new Set(); + } static getInstance(): AstNodeRevisitCache { - if (AstNodeRevisitCache.instance == undefined) { - AstNodeRevisitCache.instance = new AstNodeRevisitCache(); + if (!this.instance) { + this.instance = new AstNodeRevisitCache(); } - return AstNodeRevisitCache.instance; + return this.instance; } - reset() { - this.cache?.clear(); + reset(): void { + this._visitedTypePeers.clear(); } - has(node: arkts.AstNode) { - return this.cache?.has(node); + collect(node: arkts.AstNode | undefined): void { + if (!node) { + return; + } + this._visitedTypePeers.add(node.peer); } - collect(node: arkts.AstNode) { - if (this.cache == undefined) { - this.cache = new Set() + has(node: arkts.AstNode | undefined): boolean { + if (!node) { + return false; } - this.cache.add(node); + return this._visitedTypePeers.has(node.peer); } - - private cache: Set | undefined; -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/common/debug.ts b/ui2abc/arkui-plugins/common/debug.ts index cf9d0bb10c900a41687dde9465dc4579f86e1882..2e4f75ae3a7ee6ee6785e0dc0b42aeefa71e8751 100644 --- a/ui2abc/arkui-plugins/common/debug.ts +++ b/ui2abc/arkui-plugins/common/debug.ts @@ -15,8 +15,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as arkts from '@koalaui/libarkts'; - -// Moved from koala-wrapper +import { NodeCacheFactory } from './node-cache'; export class Debugger { private static instance: Debugger | null = null; @@ -44,16 +43,19 @@ export class Debugger { } } -// - const isDebugLog: boolean = false; const isDebugDump: boolean = false; const isPerformance: boolean = false; +const isPerformanceDetail: boolean = false; +const isNodeCacheLogPerformance: boolean = false; const enableMemoryTracker: boolean = false; const enablePhasesDebug: boolean = false; arkts.Performance.getInstance().skip(!isPerformance); arkts.Performance.getInstance().enableMemoryTracker(enableMemoryTracker); Debugger.getInstance().enablePhasesDebug(enablePhasesDebug); +arkts.Performance.getInstance().skip(!isPerformance).skipDetail(!isPerformanceDetail); +arkts.Performance.getInstance().enableMemoryTracker(enableMemoryTracker); +NodeCacheFactory.getInstance().shouldPerfLog(isNodeCacheLogPerformance); export function getEnumName(enumType: any, value: number): string | undefined { return enumType[value]; } @@ -78,35 +80,11 @@ export function debugDumpAstNode( node: arkts.AstNode, fileName: string, cachePath: string | undefined, - programFileName: string): void { + programFileName: string +): void { if (!isDebugDump) { return; - } - const currentDirectory = process.cwd(); - const modifiedFileName = programFileName.replaceAll('.', '_'); - const outputDir: string = cachePath - ? path.resolve(currentDirectory, cachePath, modifiedFileName) - : path.resolve(currentDirectory, 'dist', 'cache', modifiedFileName); - const filePath: string = path.resolve(outputDir, fileName); - if (!fs.existsSync(outputDir)) { - mkDir(outputDir); - } - try { - fs.writeFileSync(filePath, node.dumpSrc(), 'utf8'); - } catch (error) { - console.error('文件操作失败:', error); } -} - -/** @deprecated */ -export function debugDump( - content: string, - fileName: string, - isInit: boolean, - cachePath: string | undefined, - programFileName: string -): void { - if (!isDebugDump) return; const currentDirectory = process.cwd(); const modifiedFileName = programFileName.replaceAll('.', '_'); const outputDir: string = cachePath @@ -117,16 +95,7 @@ export function debugDump( mkDir(outputDir); } try { - if (!isInit && fs.existsSync(filePath)) { - const existingContent = fs.readFileSync(filePath, 'utf8'); - const newContent = - existingContent && !existingContent.endsWith('\n') - ? existingContent + '\n' + content - : existingContent + content; - fs.writeFileSync(filePath, newContent, 'utf8'); - } else { - fs.writeFileSync(filePath, content, 'utf8'); - } + fs.writeFileSync(filePath, node.dumpSrc(), 'utf8'); } catch (error) { console.error('文件操作失败:', error); } @@ -140,3 +109,40 @@ export function debugLog(message?: any, ...optionalParams: any[]): void { export function getDumpFileName(state: number, prefix: string, index: number | undefined, suffix: string): string { return `${state}_${prefix}_${index ?? ''}_${suffix}.sts`; } + +export function getPerfName(level: number[], name: string): string { + if (!isPerformanceDetail) { + return ''; + } + const levelName: string = level.join('.'); + return [levelName, name].join(' --- '); +} + +export function performanceLog( + fn: (...args: T) => R, + label: string = fn.name +): (...args: T) => R { + const timedFunction = function (this: any, ...args: T): R { + arkts.Performance.getInstance().createDetailedEvent(label); + try { + const result = fn.apply(this, args); + if (result instanceof Promise) { + return result.finally(() => { + arkts.Performance.getInstance().stopDetailedEvent(label); + }) as R; + } + arkts.Performance.getInstance().stopDetailedEvent(label); + return result; + } catch (error) { + arkts.Performance.getInstance().stopDetailedEvent(label); + throw error; + } + }; + + Object.defineProperty(timedFunction, 'name', { + value: label || fn.name, + configurable: true + }); + + return timedFunction; +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/common/declaration-collector.ts b/ui2abc/arkui-plugins/common/declaration-collector.ts index 0ac8cb543a8e8b1e7a7503606089c0cf6efe319d..e659db3450edab172e69726a53e28164840fa5d5 100644 --- a/ui2abc/arkui-plugins/common/declaration-collector.ts +++ b/ui2abc/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/ui2abc/arkui-plugins/common/file-manager.ts b/ui2abc/arkui-plugins/common/file-manager.ts index e0e8d85f4d0957f081a82ca1ae5b1080ae9ae2b1..1eb2f92d29a8a097edee20c48073d22d7c5017ca 100644 --- a/ui2abc/arkui-plugins/common/file-manager.ts +++ b/ui2abc/arkui-plugins/common/file-manager.ts @@ -1,47 +1,46 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as path from 'path'; -import { LANGUAGE_VERSION } from './predefines'; -import { readFirstLineSync, toUnixPath } from './arkts-utils'; -import { BuildConfig, DependentModuleConfig } from './plugin-context'; - - -export class FileManager { - private static instance: FileManager | undefined = undefined; - static arkTSModuleMap: Map = new Map(); - static staticApiPath: Set = new Set(); - static dynamicApiPath: Set = new Set(); - static buildConfig: BuildConfig; - private constructor() { } - - static setInstance(instance: FileManager | undefined): void { - if (instance === undefined) { - FileManager.instance = new FileManager(); - } - FileManager.instance = instance; - } - - static getInstance(): FileManager { - if (!FileManager.instance) { - FileManager.instance = new FileManager(); - } - return FileManager.instance; - } - - getLanguageVersionByFilePath(filePath: string): string { - return LANGUAGE_VERSION.ARKTS_1_2; - } -} \ No newline at end of file +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { LANGUAGE_VERSION } from './predefines'; +import { readFirstLineSync, toUnixPath } from './arkts-utils'; +import { BuildConfig, DependentModuleConfig } from './plugin-context'; + +export class FileManager { + private static instance: FileManager | undefined = undefined; + static arkTSModuleMap: Map = new Map(); + static staticApiPath: Set = new Set(); + static dynamicApiPath: Set = new Set(); + static buildConfig: BuildConfig; + private constructor() {} + + static setInstance(instance: FileManager | undefined): void { + if (instance === undefined) { + FileManager.instance = new FileManager(); + } + FileManager.instance = instance; + } + + static getInstance(): FileManager { + if (!FileManager.instance) { + FileManager.instance = new FileManager(); + } + return FileManager.instance; + } + + getLanguageVersionByFilePath(filePath: string): string { + return LANGUAGE_VERSION.ARKTS_1_2; + } +} diff --git a/ui2abc/arkui-plugins/common/import-collector.ts b/ui2abc/arkui-plugins/common/import-collector.ts index 6705ee925afd9d23a91403ae6b7418843fc08a9c..9a47b080804dd0b3140de045888610e73223a9b0 100644 --- a/ui2abc/arkui-plugins/common/import-collector.ts +++ b/ui2abc/arkui-plugins/common/import-collector.ts @@ -57,10 +57,14 @@ export class ImportCollector { } reset(): void { - this.importInfos = []; - this.imported.clear(); this.localMap.clear(); this.sourceMap.clear(); + this.clearImports(); + } + + clearImports(): void { + this.importInfos = []; + this.imported.clear(); } collectSource(imported: string, source: string): void { diff --git a/ui2abc/arkui-plugins/common/log-collector.ts b/ui2abc/arkui-plugins/common/log-collector.ts index 3cd1d9ecd5699db618a12d99b7fc35b07172483f..3ad2c48eb58e2a4fab79782bdc62005807b19365 100644 --- a/ui2abc/arkui-plugins/common/log-collector.ts +++ b/ui2abc/arkui-plugins/common/log-collector.ts @@ -16,20 +16,70 @@ 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]; + title?: string; + 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, + title?: string, + ...args: string[] +): SuggestionOptions { + return { code, range: [rangeStart, rangeEnd], title, args }; +} + +export function getPositionRangeFromNode(node: arkts.AstNode): [arkts.SourcePosition, arkts.SourcePosition] { + return [node.startPosition, node.endPosition]; +} + +// 开始位置前移一格,以包含@字符 +export function getPositionRangeFromAnnotation(node: arkts.AstNode): [arkts.SourcePosition, arkts.SourcePosition] { + return [arkts.createSourcePosition(node.startPosition.getIndex() - 1, node.startPosition.getLine()), node.endPosition]; } export function generateDiagnosticKind(logItem: LogInfo): arkts.DiagnosticKind { - return arkts.createDiagnosticKind( - `${logItem.code}: ${logItem.message}`, - logItem.type === LogType.ERROR + const message: string = !!logItem.code ? `${logItem.code}: ${logItem.message}` : logItem.message; + const level: arkts.Es2pandaPluginDiagnosticType = + logItem.level === LogType.ERROR ? arkts.Es2pandaPluginDiagnosticType.ES2PANDA_PLUGIN_ERROR - : arkts.Es2pandaPluginDiagnosticType.ES2PANDA_PLUGIN_WARNING - ); + : arkts.Es2pandaPluginDiagnosticType.ES2PANDA_PLUGIN_WARNING; + return arkts.createDiagnosticKind(message, level); +} + +export function generateDiagnosticInfo(logItem: LogInfo, pos: arkts.SourcePosition): arkts.DiagnosticInfo { + const diagnosticArgs = logItem.args ?? []; + const diagnosticKind = generateDiagnosticKind(logItem); + return arkts.createDiagnosticInfo(diagnosticKind, pos, ...diagnosticArgs); +} + +export function generateSuggestionInfo( + suggestion: SuggestionOptions, + message: string, + range: arkts.SourceRange +): arkts.SuggestionInfo { + const suggestionArgs = suggestion.args ?? []; + const suggestionKind = arkts.createDiagnosticKind(message, arkts.Es2pandaPluginDiagnosticType.ES2PANDA_PLUGIN_SUGGESTION); + return arkts.createSuggestionInfo(suggestionKind, suggestion.code, message, range, ...suggestionArgs); +} + +export function generateSuggestionRange(suggestion: SuggestionOptions): arkts.SourceRange { + const [startPosition, endPosition] = suggestion.range; + return arkts.createSourceRange(startPosition, endPosition); } export class LogCollector { @@ -49,6 +99,21 @@ export class LogCollector { return this.instance; } + private reportDiagnostic(log: LogInfo): void { + const args = log.args ?? []; + const position = log.position ?? log.node.startPosition; + const suggestion = log.suggestion; + if (!suggestion) { + const kind = generateDiagnosticKind(log); + arkts.logDiagnostic(kind, position, ...args); + } else { + const info = generateDiagnosticInfo(log, position); + const suggestionRange = generateSuggestionRange(suggestion); + const suggestionInfo = generateSuggestionInfo(suggestion, log.message, suggestionRange); + arkts.logDiagnosticWithSuggestion(info, suggestionInfo); + } + } + reset(): void { this.logInfos = []; this.ignoreError = false; @@ -63,7 +128,7 @@ export class LogCollector { return; } this.logInfos.forEach((logItem: LogInfo) => { - arkts.logDiagnostic(generateDiagnosticKind(logItem), logItem.node.startPosition); + this.reportDiagnostic(logItem); }); } diff --git a/ui2abc/arkui-plugins/common/metadata-collector.ts b/ui2abc/arkui-plugins/common/metadata-collector.ts index 9f12ec95b19bfb58331b9d19022e63cc2fdef6b7..e3b46c47f7ad1f45d9cb04246e3b6478b0007825 100644 --- a/ui2abc/arkui-plugins/common/metadata-collector.ts +++ b/ui2abc/arkui-plugins/common/metadata-collector.ts @@ -13,12 +13,16 @@ * limitations under the License. */ -import { ProjectConfig } from './plugin-context'; +import { ConsistentResourceMap, ProjectConfig, ResourceInfo, UIComponents } from './plugin-context'; export class MetaDataCollector { + public resourceInfo: ResourceInfo | undefined; public projectConfig: ProjectConfig | undefined; public fileAbsName: string | undefined; public externalSourceName: string | undefined; + public componentsInfo: UIComponents | undefined; + public consistentResourceMap: ConsistentResourceMap | undefined; + public mainPageNames: string[] | undefined; private static instance: MetaDataCollector | null = null; static getInstance(): MetaDataCollector { @@ -43,9 +47,33 @@ export class MetaDataCollector { return this; } + setResourceInfo(resourceInfo: ResourceInfo | undefined): this { + this.resourceInfo = resourceInfo; + return this; + } + + setComponentsInfo(componentsInfo: UIComponents | undefined): this { + this.componentsInfo = componentsInfo; + return this; + } + + setConsistentResourceMap(resourceMap: ConsistentResourceMap | undefined): this { + this.consistentResourceMap = resourceMap; + return this; + } + + setMainPages(mainPages: string[] | undefined): this { + this.mainPageNames = mainPages; + return this; + } + reset(): void { this.projectConfig = undefined; this.fileAbsName = undefined; this.externalSourceName = undefined; + this.resourceInfo = undefined; + this.componentsInfo = undefined; + this.consistentResourceMap = undefined; + this.mainPageNames = undefined; } -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/common/node-cache.ts b/ui2abc/arkui-plugins/common/node-cache.ts index 4b18d966014395f28a80dfeed82163b4cc1b4569..a08f463d4830d419cc974569f36e0fbbea2b49e0 100644 --- a/ui2abc/arkui-plugins/common/node-cache.ts +++ b/ui2abc/arkui-plugins/common/node-cache.ts @@ -14,6 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; +import { NodeCacheNames } from "./predefines"; export interface AstNodeCacheValue { peer: arkts.KNativePointer; @@ -21,61 +22,150 @@ export interface AstNodeCacheValue { metadata?: AstNodeCacheValueMetadata; } -export interface AstNodeCacheValueMetadata { - callName?: string; - hasReceiver?: boolean; - isSetter?: boolean; - isGetter?: boolean; - forbidTypeRewrite?: boolean; - isWithinTypeParams?: boolean; - hasMemoSkip?: boolean; - hasMemoIntrinsic?: boolean; - hasMemoEntry?: boolean; +export type AstNodeCacheValueMetadata = { + [key in string]?: any; } +function traverseASTSync( + left: arkts.AstNode, + right: arkts.AstNode, + callbackFn: (left: arkts.AstNode, right: arkts.AstNode) => boolean +): void { + const shouldStop = callbackFn(left, right); + if (shouldStop) { + return; + } + const leftChildren = left.getChildren(); + const rightChildren = right.getChildren(); + for (let i = 0; i < leftChildren.length; i++) { + traverseASTSync(leftChildren[i], rightChildren[i], callbackFn); + } +} + +export function copyCacheToClonedNode(original: arkts.AstNode, cloned: arkts.AstNode, shouldRefresh?: boolean): void { + const traverseCallbackFn = (_original: arkts.AstNode, _cloned: arkts.AstNode): boolean => { + if (!NodeCacheFactory.currentCacheKey) { + return true; + } + const key: string = NodeCacheFactory.currentCacheKey; + const cache: NodeCache = NodeCacheFactory.getInstance().getCache(key); + if (!cache.has(_original)) { + return false; + } + if (shouldRefresh) { + cache.refresh(_original, _cloned); + } else { + const value = cache.get(_original)!; + cache.collect(_cloned, value.metadata); + + } + return cache.shouldUpdateByPeer(_cloned.peer); + }; + traverseASTSync(original, cloned, traverseCallbackFn); +} + +// Add hook to update cache on clone calls. Please refactor +((orig, origOnUpdate) => { + arkts.AstNode.prototype.clone = function () { + const cloned = orig.call(this); + copyCacheToClonedNode(this, cloned); + return cloned; + }; + + arkts.AstNode.prototype.onUpdate = function (original: arkts.AstNode) { + origOnUpdate.call(this, original); + NodeCacheFactory.getInstance().refresh(original, this); + NodeCacheFactory.getInstance().refreshUpdate(original, this); + }; +})(arkts.AstNode.prototype.clone, arkts.AstNode.prototype.onUpdate); + + export class NodeCache { + private _shouldPerfLog: boolean = false; private _isCollected: boolean = false; + private _shouldCollectUpdate: boolean = false; + private _shouldCollect: boolean = true; private cacheMap: Map; - private static instance: arkts.MemoNodeCache; + private nodesToUpdate: Set; - private constructor() { + constructor(private id: string) { this.cacheMap = new Map(); + this.nodesToUpdate = new Set(); } - static getInstance(): arkts.MemoNodeCache { - if (!this.instance) { - this.instance = arkts.MemoNodeCache.getInstance() - } - - // Please provide the another way to force cache update on when node updates - wrapFuncWithNodeCache(this.instance, "updateArrowFunctionExpression") - wrapFuncWithNodeCache(this.instance, "updateBreakStatement") - wrapFuncWithNodeCache(this.instance, "updateCallExpression") - wrapFuncWithNodeCache(this.instance, "updateClassProperty") - wrapFuncWithNodeCache(this.instance, "updateETSFunctionType") - wrapFuncWithNodeCache(this.instance, "updateETSParameterExpression") - wrapFuncWithNodeCache(this.instance, "updateETSUnionType") - wrapFuncWithNodeCache(this.instance, "updateIdentifier") - wrapFuncWithNodeCache(this.instance, "updateMethodDefinition") - wrapFuncWithNodeCache(this.instance, "updateProperty") - wrapFuncWithNodeCache(this.instance, "updateReturnStatement") - wrapFuncWithNodeCache(this.instance, "updateScriptFunction") - wrapFuncWithNodeCache(this.instance, "updateTSTypeAliasDeclaration") - wrapFuncWithNodeCache(this.instance, "updateVariableDeclarator") + shouldPerfLog(shouldLog: boolean): this { + this._shouldPerfLog = shouldLog; + return this; + } - return this.instance; + shouldCollect(shouldCollect: boolean): this { + this._shouldCollect = shouldCollect; + return this; + } + + shouldCollectUpdate(shouldCollectUpdate: boolean): this { + this._shouldCollectUpdate = shouldCollectUpdate; + return this; } collect(node: arkts.AstNode, metadata?: AstNodeCacheValueMetadata): void { + if (!this._shouldCollect) { + return; + } + if (this._shouldCollectUpdate) { + this._collectNodesToUpdate(node, node.parent); + } + this._collect(node, metadata); + } + + shouldUpdate(node: arkts.AstNode): boolean { + if (!this._shouldCollectUpdate) { + return true; + } + return this.nodesToUpdate.has(node.peer); + } + + shouldUpdateByPeer(peer: arkts.KNativePointer): boolean { + if (!this._shouldCollectUpdate) { + return true; + } + return this.nodesToUpdate.has(peer); + } + + addNodeToUpdate(node: arkts.AstNode): void { + if (!this._isCollected && !this._shouldCollectUpdate) { + return; + } + this.nodesToUpdate.add(node.peer); + } + + addNodeToUpdateByPeer(peer: arkts.KNativePointer): void { + if (!this._isCollected && !this._shouldCollectUpdate) { + return; + } + this.nodesToUpdate.add(peer); + } + + private _collect(node: arkts.AstNode, metadata?: AstNodeCacheValueMetadata): void { const peer = node.peer; - const type = arkts.arktsGlobal.generatedEs2panda._AstNodeTypeConst(arkts.arktsGlobal.context, node.peer); + const type = node.astNodeType; let currMetadata: AstNodeCacheValueMetadata | undefined = metadata ?? {}; if (this.cacheMap.has(peer)) { const oldMetadata = this.cacheMap.get(peer)!.metadata ?? {}; currMetadata = { ...oldMetadata, ...currMetadata }; } currMetadata = Object.keys(currMetadata).length === 0 ? undefined : currMetadata; - this.cacheMap.set(peer, { peer, type, metadata: currMetadata }); + this.cacheMap.set(peer, { peer, type, metadata: currMetadata }); + this._isCollected = true; + } + + private _collectNodesToUpdate(node: arkts.AstNode, parent?: arkts.AstNode): void { + this.nodesToUpdate.add(node.peer); + let currParent: arkts.AstNode | undefined = parent; + while (!!currParent && !this.nodesToUpdate.has(currParent.peer)) { + this.nodesToUpdate.add(currParent.peer); + currParent = currParent.parent; + } this._isCollected = true; } @@ -85,13 +175,29 @@ export class NodeCache { metadata = this.get(original)?.metadata; this.cacheMap.delete(original.peer); } - this.collect(node, metadata); + this._collectNodesToUpdate(node); + this._collect(node, metadata); + } + + refreshUpdate(original: arkts.AstNode, node: arkts.AstNode): void { + if (this.shouldUpdate(original)) { + this.nodesToUpdate.delete(original.peer); + } + this._collectNodesToUpdate(node, original.parent); } isCollected(): boolean { return this._isCollected; } + isCollectEnabled(): boolean { + return this._shouldCollect; + } + + isCollectUpdateEnabled(): boolean { + return this._shouldCollectUpdate; + } + has(node: arkts.AstNode): boolean { return this.cacheMap.has(node.peer); } @@ -102,31 +208,205 @@ export class NodeCache { clear(): void { this.cacheMap.clear(); + this.nodesToUpdate.clear(); this._isCollected = false; } visualize(): void { Array.from(this.cacheMap.values()).forEach(({ peer, type, metadata }) => { - const src = arkts.arktsGlobal.generatedEs2panda._AstNodeDumpEtsSrcConst(arkts.arktsGlobal.context, peer) + const src = arkts.arktsGlobal.generatedEs2panda._AstNodeDumpEtsSrcConst(arkts.arktsGlobal.context, peer); + const shouldUpdate = this.nodesToUpdate.has(peer); console.log( - `[NODE CACHE] ptr ${peer}, type: ${type}, metadata: ${JSON.stringify(metadata)}, node: `, - arkts.unpackString(src) + `[NODE CACHE] ptr ${peer}, type: ${type}, shouldUpdate: ${shouldUpdate}, metadata: ${JSON.stringify(metadata)}, node: `, + src ); }); } + + perfLog(key?: string): void { + if (!this._shouldPerfLog) { + return; + } + if (!!key) { + console.log("[PERFORMANCE] [NODE CACHE] cache key: ", key); + } + console.log(`[PERFORMANCE] [NODE CACHE] cached-node count: `, Object.keys(this.cacheMap).length); + console.log(`[PERFORMANCE] [NODE CACHE] should-update-node count: `, this.nodesToUpdate.size); + } } -function wrapFuncWithNodeCache(cache: arkts.MemoNodeCache, funcName: keyof typeof arkts.factory) { - if ((funcName+"__orig") in arkts.factory) return; +class MemoNodeCache extends NodeCache { + shouldPerfLog(shouldLog: boolean): this { + console.warn(`[NODE CACHE] arkts.MemoNodeCache does not support: shouldPerfLog`); + return this + } + + shouldCollect(shouldCollect: boolean): this { + throw new Error("Not supported"); + } + + shouldCollectUpdate(shouldCollectUpdate: boolean): this { + arkts.MemoNodeCache.getInstance().shouldCollectUpdate(shouldCollectUpdate); + return this; + } + + collect(node: arkts.AstNode, metadata?: AstNodeCacheValueMetadata): void { + arkts.MemoNodeCache.getInstance().collect(node, metadata); + } + + shouldUpdate(node: arkts.AstNode): boolean { + return arkts.MemoNodeCache.getInstance().shouldUpdate(node); + } + + shouldUpdateByPeer(peer: arkts.KNativePointer): boolean { + return arkts.MemoNodeCache.getInstance().shouldUpdateByPeer(peer); + } + + addNodeToUpdate(node: arkts.AstNode): void { + throw new Error("Not supported"); + } + + addNodeToUpdateByPeer(peer: arkts.KNativePointer): void { + arkts.MemoNodeCache.getInstance().addNodeToUpdateByPeer(peer); + } - let orig = arkts.factory[funcName] as any; - let wrapped = function (this: any, original: arkts.AstNode, ...args: any[]) { - let newNode = orig.call(this, original, ...args); - if (cache.has(original)) { - cache.refresh(original, newNode); + refresh(original: arkts.AstNode, node: arkts.AstNode): void { + arkts.MemoNodeCache.getInstance().refresh(original, node); + } + + refreshUpdate(original: arkts.AstNode, node: arkts.AstNode): void { + arkts.MemoNodeCache.getInstance().refreshUpdate(original, node); + } + + isCollected(): boolean { + return arkts.MemoNodeCache.getInstance().isCollected(); + } + + isCollectEnabled(): boolean { + throw new Error("Not supported"); + } + + isCollectUpdateEnabled(): boolean { + throw new Error("Not supported"); + } + + has(node: arkts.AstNode): boolean { + return arkts.MemoNodeCache.getInstance().has(node); + } + + get(node: arkts.AstNode): AstNodeCacheValue | undefined { + return arkts.MemoNodeCache.getInstance().get(node); + } + + clear(): void { + arkts.MemoNodeCache.getInstance().clear(); + } + + visualize(): void { + arkts.MemoNodeCache.getInstance().visualize(); + } + + perfLog(key?: string): void { + console.warn(`[NODE CACHE] arkts.MemoNodeCache does not support: perfLog`); + } +} + +export class NodeCacheFactory { + private _shouldPerfLog: boolean = false; + private cacheMap: Map; + private static instance: NodeCacheFactory; + + static currentCacheKey: string | undefined; + + private constructor() { + this.cacheMap = new Map(); + } + + static getInstance(): NodeCacheFactory { + if (!this.instance) { + this.instance = new NodeCacheFactory(); } - return newNode - }; - (arkts.factory as any)[funcName] = wrapped as any; - (arkts.factory as any)[funcName+"__orig"] = orig as any; -} \ No newline at end of file + return this.instance; + } + + shouldPerfLog(shouldLog: boolean): this { + this._shouldPerfLog = shouldLog; + return this; + } + + getCacheMap(): Map { + return this.cacheMap; + } + + getCache(key: string): NodeCache { + if (!this.cacheMap.has(key)) { + if (key == NodeCacheNames.MEMO) { + this.cacheMap.set(key, new MemoNodeCache(key)); + } else { + this.cacheMap.set(key, new NodeCache(key)); + } + } + return this.cacheMap.get(key)!; + } + + clear(): void { + this.cacheMap.forEach((cache) => { + cache.clear(); + }); + this.cacheMap = new Map(); + } + + has(node: arkts.AstNode, key?: string): boolean { + if (!!key) { + return !!this.cacheMap.get(key)?.has(node); + } + return Array.from(this.cacheMap.values()).some((cache) => cache.has(node)); + } + + shouldUpdate(node: arkts.AstNode, key?: string): boolean { + if (!!key) { + return !!this.cacheMap.get(key)?.shouldUpdate(node); + } + return Array.from(this.cacheMap.values()).some((cache) => cache.shouldUpdate(node)); + } + + refresh(original: arkts.AstNode, node: arkts.AstNode, key?: string): void { + if (!!key) { + const cache: NodeCache | undefined = this.cacheMap.get(key); + if (!!cache && cache.has(original)) { + cache.refresh(original, node); + } + return; + } + this.cacheMap.forEach((cache) => { + if (cache.has(original)) { + cache.refresh(original, node); + } + }); + } + + refreshUpdate(original: arkts.AstNode, node: arkts.AstNode, key?: string): void { + if (!!key) { + const cache: NodeCache | undefined = this.cacheMap.get(key); + if (!!cache && cache.shouldUpdate(original)) { + cache.refreshUpdate(original, node); + } + return; + } + this.cacheMap.forEach((cache) => { + if (cache.shouldUpdate(original)) { + cache.refreshUpdate(original, node); + } + }); + } + + perfLog(key: string, shouldLog: boolean = false): void { + if (!shouldLog) { + return; + } + if (!this.cacheMap.has(key)) { + return; + } + this.cacheMap.get(key)!.shouldPerfLog(this._shouldPerfLog).perfLog(key); + } +} diff --git a/ui2abc/arkui-plugins/common/plugin-context.ts b/ui2abc/arkui-plugins/common/plugin-context.ts index d22f595b2a5ce5a620da8b74fa82419bd3a18831..c2c826ed06be5f7577baa23465745c744f753b67 100644 --- a/ui2abc/arkui-plugins/common/plugin-context.ts +++ b/ui2abc/arkui-plugins/common/plugin-context.ts @@ -26,6 +26,55 @@ export type PluginState = arkts.PluginState export type PluginExecutor = arkts.PluginExecutor export type BuildConfig = arkts.BuildConfig +// RESOURCE TYPES +export type ResourceMap = Map>; + +export interface ResourceList { + [key: string]: ResourceMap; +} + +export interface ResourceInfo { + resourcesList: ResourceList; + rawfile: Set; +} + export interface UIPluginOptions { - namedOverloads?: boolean; -} \ No newline at end of file + namedOverloads?: boolean; +} + +export type ConsistentResourceMap = Map; + +export type ConsistentResourceInfo = { + id: string; + resourceName: string; +} + +// UI COMPONENT TYPES +export interface UIComponents { + builtInAttributes: string[]; + containerComponents: string[]; + atomicComponents: string[]; + singleChildComponents: string[]; + validParentComponent: Map; + validChildComponent: Map; +} + +export interface ComponentJson { + name: string; + atomic?: boolean; + attrs: string[]; + single?: boolean; + parents?: string[]; + children?: string[]; +} + +// APPLICATION MAIN PAGE TYPES +export type ApplicationModuleConfig = { + module: { + pages: string; + }; +}; + +export type ApplicationMainPages = { + src: string[]; +}; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/common/predefines.ts b/ui2abc/arkui-plugins/common/predefines.ts index e37cd76ba57015694c71160872261bc8b343f6f0..473727b3dc60bc89e2c79f1d357bac94b947767e 100644 --- a/ui2abc/arkui-plugins/common/predefines.ts +++ b/ui2abc/arkui-plugins/common/predefines.ts @@ -13,13 +13,27 @@ * limitations under the License. */ -export const EXTERNAL_SOURCE_PREFIX_NAMES: (string | RegExp)[] = [ +import * as path from 'path' + +export const LINTER_EXCLUDE_EXTERNAL_SOURCE_PREFIXES: Array = [ 'std', 'escompat', + 'security', + 'application', + 'permissions', + 'bundleManager', + 'commonEvent', + 'global', + 'arkui', /@arkts\..*/, + /@ohos\.*/, /@system\..*/, + /@koalaui\./, + /ability\..*/, ]; +export const EXTERNAL_SOURCE_PREFIX_NAMES: (string | RegExp)[] = ['std', 'escompat', /@arkts\..*/, /@system\..*/]; + export const EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK: (string | RegExp)[] = [ 'std', 'escompat', @@ -33,13 +47,23 @@ export const MEMO_IMPORT_SOURCE_NAME: string = 'arkui.incremental.annotation'; export const MEMO_SKIP_UI_IMPORT_SOURCE_NAME: string = 'arkui.incremental.annotation'; export const CUSTOM_COMPONENT_IMPORT_SOURCE_NAME: string = 'arkui.component.customComponent'; export const CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME: string = 'arkui.component.customDialogController'; -export const ENTRY_POINT_IMPORT_SOURCE_NAME: string = 'arkui.component.customComponent'; export const ARKUI_COMPONENT_COMMON_SOURCE_NAME: string = 'arkui.component.common'; export const ARKUI_FOREACH_SOURCE_NAME: string = 'arkui.component.forEach'; export const ARKUI_BUILDER_SOURCE_NAME: string = 'arkui.component.builder'; +export const ARKUI_INTEROP_SOURCE_NAME: string = 'arkui.component.interop'; export const RESOURCE_IMPORT_SOURCE_NAME: string = 'arkui.component.resources'; +export const LIB_UI_COMPONENTS_PATH: string = path.resolve(__dirname, '../components'); +export const PREVIEWER_RESOURCE_PATH: string = path.resolve( + __dirname, + '../../../../../../previewer/common/resources/entry/resources.txt' +); +export const PREVIEWER_RESOURCE_SKIP_PREFIX_NAMES: string[] = ['ohos_id', 'ohos_fa']; +export const APPLICATION_MAIN_BASE_RESOURCE_PATH = 'src/main/resources/base'; +export const APPLICATION_MAIN_ETS_PATH = 'src/main/ets'; + export enum ModuleType { + DOLLAR = '$', HAR = 'har', ENTRY = 'entry', FEATURE = 'feature', @@ -59,7 +83,6 @@ export enum LogType { } export enum Dollars { - DOLLAR = '$', DOLLAR_RESOURCE = '$r', DOLLAR_RAWFILE = '$rawfile', DOLLAR_DOLLAR = '$$', @@ -68,9 +91,10 @@ export enum Dollars { } export enum BindableNames { + MAKE_BINDABLE = 'makeBindable', BINDABLE = 'Bindable', VALUE = 'value', - ON_CHANGE = 'onChange' + ON_CHANGE = 'onChange', } export enum StructDecoratorNames { @@ -81,6 +105,9 @@ export enum StructDecoratorNames { RESUABLE_V2 = 'ReusableV2', CUSTOM_LAYOUT = 'CustomLayout', CUSTOMDIALOG = 'CustomDialog', + PREVIEW = 'Preview', + REUSABLE = 'Reusable', + REUSABLE_V2 = 'ReusableV2' } export enum EntryWrapperNames { @@ -91,7 +118,7 @@ export enum EntryWrapperNames { REGISTER_NAMED_ROUTER = 'RegisterNamedRouter', ROUTER_NAME = 'routerName', INSTANCE = 'instance', - PARAM = 'param' + PARAM = 'param', } export enum ObservedNames { @@ -103,7 +130,7 @@ export enum ObservedNames { ADD_REF = 'addRef', SHOULD_ADD_REF = 'shouldAddRef', NEW_NAME = 'newName', - PROPERTY_PREFIX = '', + PROPERTY_PREFIX = '%%property-', NEW_VALUE = 'newValue', FIRE_CHANGE = 'fireChange', EXECUATE_WATCHES = 'executeOnSubscribingWatches', @@ -119,7 +146,7 @@ export enum MonitorNames { export enum EntryParamNames { ENTRY_STORAGE = 'storage', ENTRY_USE_SHARED_STORAGE = 'useSharedStorage', - ENTRY_ROUTE_NAME = 'routeName' + ENTRY_ROUTE_NAME = 'routeName', } export enum InnerComponentNames { @@ -166,7 +193,9 @@ export enum DecoratorNames { COMPUTED = 'Computed', EVENT = 'Event', REQUIRE = 'Require', - TYPE = 'Type', + REGULAR = 'Regular', + VARIABLE = 'Variable', + TYPE = 'Type' } export enum TypeNames { @@ -177,10 +206,6 @@ export enum TypeNames { STRING = 'string', } -export enum DecoratorIntrinsicNames { - LINK = '__Link_intrinsic', -} - export enum StateManagementTypes { STATE_MANAGEMENT_FACTORY = 'STATE_MGMT_FACTORY', STATE_DECORATED = 'IStateDecoratedVariable', @@ -237,6 +262,7 @@ export enum StateManagementTypes { MAKE_OBSERVED = 'makeObserved', MAKE_BUILDER_PARAM_PROXY = 'makeBuilderParameterProxy', SET_OWNER = 'setOwner', + BACKING = '__backing', } export enum AnimationNames { @@ -261,10 +287,6 @@ export enum ConditionNames { CONDITION_BRANCH = 'ConditionBranch', } -export enum ArkTsDefaultNames { - DEFAULT_STATIC_BLOCK_NAME = '', -} - export const RESOURCE_TYPE: Record = { color: 10001, float: 10002, @@ -301,17 +323,39 @@ export const DECORATOR_TYPE_MAP = new Map( export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map([ [Dollars.DOLLAR_RESOURCE, [Dollars.TRANSFORM_DOLLAR_RESOURCE]], [Dollars.DOLLAR_RAWFILE, [Dollars.TRANSFORM_DOLLAR_RAWFILE]], - [Dollars.DOLLAR_DOLLAR, [BindableNames.BINDABLE]], + [Dollars.DOLLAR_DOLLAR, [BindableNames.BINDABLE, BindableNames.MAKE_BINDABLE]], [DecoratorNames.STATE, [StateManagementTypes.STATE_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.LINK, [StateManagementTypes.LINK_DECORATED, StateManagementTypes.LINK_SOURCE_TYPE, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], + [ + DecoratorNames.LINK, + [ + StateManagementTypes.LINK_DECORATED, + StateManagementTypes.LINK_SOURCE_TYPE, + StateManagementTypes.STATE_MANAGEMENT_FACTORY, + ], + ], [DecoratorNames.PROP_REF, [StateManagementTypes.PROP_REF_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], [DecoratorNames.PROVIDE, [StateManagementTypes.PROVIDE_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], [DecoratorNames.CONSUME, [StateManagementTypes.CONSUME_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.STORAGE_PROP_REF, [StateManagementTypes.STORAGE_PROP_REF_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.LOCAL_STORAGE_PROP_REF, [StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.STORAGE_LINK, [StateManagementTypes.STORAGE_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.OBJECT_LINK, [StateManagementTypes.OBJECT_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], - [DecoratorNames.LOCAL_STORAGE_LINK, [StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], + [ + DecoratorNames.STORAGE_PROP_REF, + [StateManagementTypes.STORAGE_PROP_REF_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY], + ], + [ + DecoratorNames.LOCAL_STORAGE_PROP_REF, + [StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY], + ], + [ + DecoratorNames.STORAGE_LINK, + [StateManagementTypes.STORAGE_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY], + ], + [ + DecoratorNames.OBJECT_LINK, + [StateManagementTypes.OBJECT_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY], + ], + [ + DecoratorNames.LOCAL_STORAGE_LINK, + [StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY], + ], [DecoratorNames.LOCAL, [StateManagementTypes.LOCAL_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], [DecoratorNames.PARAM, [StateManagementTypes.PARAM_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], [DecoratorNames.ONCE, [StateManagementTypes.ONCE_DECORATED, StateManagementTypes.STATE_MANAGEMENT_FACTORY]], @@ -328,7 +372,7 @@ export const INTERMEDIATE_IMPORT_SOURCE: Map = new Map = new Map = new Map = new Map = new Map([ [Dollars.TRANSFORM_DOLLAR_RESOURCE, 'arkui.component.resources'], [Dollars.TRANSFORM_DOLLAR_RAWFILE, 'arkui.component.resources'], - [StateManagementTypes.STORAGE_LINK_STATE, ''], - [StateManagementTypes.OBSERVABLE_PROXY, ''], - [StateManagementTypes.PROP_STATE, ''], + [StateManagementTypes.STORAGE_LINK_STATE, 'arkui.stateManagement.runtime'], + [StateManagementTypes.OBSERVABLE_PROXY, 'arkui.stateManagement.runtime'], + [StateManagementTypes.PROP_STATE, 'arkui.stateManagement.runtime'], [StateManagementTypes.UI_UTILS, 'arkui.stateManagement.utils'], - [AnimationNames.ANIMATABLE_ARITHMETIC, 'arkui.component.common'] + [AnimationNames.ANIMATABLE_ARITHMETIC, 'arkui.component.common'], ]); export enum GetSetTypes { @@ -382,13 +420,63 @@ export enum GetSetTypes { SET = 'set', } -export enum GenSymPrefix { - INTRINSIC = 'gensym%%', - UI = 'gensym__' +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 = '%%property-', + DEFAULT_STATIC_BLOCK_NAME = '', } export enum LANGUAGE_VERSION { ARKTS_1_2 = '1.2', ARKTS_1_1 = '1.1', ARKTS_HYBRID = 'hybrid', -}; \ No newline at end of file +} + +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_TO_RECORD = '__toRecord', + COMPONENT_INITIALIZERS_NAME = 'initializers', + BUILDCOMPATIBLENODE = '_buildCompatibleNode', + OPTIONS = 'options', + PAGE_LIFE_CYCLE = 'PageLifeCycle', + LAYOUT_CALLBACKS = 'LayoutCallbacks', +} + +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', + COMPONENT_PARAM_ORI = 'content_', + APPLY_ATTRIBUTES_FINISH_METHOD = 'applyAttributesFinish', +} + +export enum NodeCacheNames { + MEMO = 'memo', + UI = 'ui', +} diff --git a/ui2abc/arkui-plugins/common/program-skipper.ts b/ui2abc/arkui-plugins/common/program-skipper.ts index 99d9c6239382c8ba58d5e39140b5bbf788bd968a..985ff749d47adedea012455cc16591be0886043e 100644 --- a/ui2abc/arkui-plugins/common/program-skipper.ts +++ b/ui2abc/arkui-plugins/common/program-skipper.ts @@ -16,6 +16,8 @@ import * as arkts from '@koalaui/libarkts'; import { debugLog } from './debug'; import * as path from 'path'; +import { AstNodePointer } from './safe-types'; + import { PluginContext } from './plugin-context'; const LIB_SUFFIX = '.d.ets'; @@ -23,8 +25,8 @@ const ARKUI = 'arkui'; export class ProgramSkipper { private static _absName2programs: Map = new Map(); - private static _uiProgramSet: Set = new Set(); - private static _edges: Map = new Map(); + private static _uiProgramSet: Set = new Set(); + private static _edges: Map = new Map(); private static _initedCanSkip: boolean = false; private static dfs(program: arkts.Program): void { @@ -72,10 +74,11 @@ export class ProgramSkipper { return; } const start = performance.now(); - programs.forEach(p => this.addProgramToMap(p)); - programs.forEach(p => this.addEdges(p)); - programs.forEach(p => { - if (p.absoluteName.endsWith(LIB_SUFFIX) && p.absoluteName.includes(ARKUI)) { + programs.forEach((p) => this.addProgramToMap(p)); + programs.forEach((p) => this.addEdges(p)); + programs.forEach((p) => { + const name = p.absoluteName; + if (name.endsWith(LIB_SUFFIX) && name.includes(ARKUI)) { this.dfs(p); } }); @@ -89,15 +92,21 @@ export class ProgramSkipper { } public static canSkipProgram(program: arkts.Program | undefined): boolean { - if (!arkts.arktsGlobal.configObj || - arkts.arktsGlobal.configObj.compilationMode !== arkts.Es2pandaCompilationMode.COMPILATION_MODE_GEN_ABC_FOR_EXTERNAL_SOURCE) { + if ( + !arkts.arktsGlobal.configObj || + arkts.arktsGlobal.configObj.compilationMode !== + arkts.Es2pandaCompilationMode.COMPILATION_MODE_GEN_ABC_FOR_EXTERNAL_SOURCE + ) { return false; } if (!program) { return false; } if (!this._initedCanSkip) { - const programs = [...arkts.arktsGlobal.compilerContext?.program.getExternalSources().flatMap(s => s.programs)!, program]; + const programs = [ + ...arkts.arktsGlobal.compilerContext?.program.getExternalSources().flatMap((s) => s.programs)!, + program, + ]; this.initCanSkip(programs); this._initedCanSkip = true; this._absName2programs.clear(); @@ -114,4 +123,4 @@ export function captureProgramSkipperToPluginContext(context: PluginContext) { context.setParameter(PROGRAM_SKIPPER_FUNCTION_PARAMETER_NAME, (program: arkts.Program) => { return ProgramSkipper.canSkipProgram(program) }) -} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/common/program-visitor.ts b/ui2abc/arkui-plugins/common/program-visitor.ts index 5fa3a226075a3479d857ee4106a6f83f6c35d575..21309797ab773c06b7b53ec1882f34e584ae73ef 100644 --- a/ui2abc/arkui-plugins/common/program-visitor.ts +++ b/ui2abc/arkui-plugins/common/program-visitor.ts @@ -18,10 +18,12 @@ import { AbstractVisitor, VisitorOptions } from './abstract-visitor'; import { matchPrefix } from './arkts-utils'; import { getDumpFileName, debugDumpAstNode, debugLog } from './debug'; import { PluginContext } from './plugin-context'; -import { LegacyTransformer } from '../ui-plugins/interop/legacy-transformer'; import { ProgramSkipper } from './program-skipper'; +import { InteroperAbilityNames } from '../ui-plugins/interop/predefines'; +import { LegacyTransformer } from '../ui-plugins/interop/legacy-transformer'; import { FileManager } from './file-manager'; import { LANGUAGE_VERSION } from './predefines'; +import { ComponentTransformer } from '../ui-plugins/component-transformer'; export interface ProgramVisitorOptions extends VisitorOptions { pluginName: string; @@ -30,7 +32,7 @@ export interface ProgramVisitorOptions extends VisitorOptions { skipPrefixNames: (string | RegExp)[]; hooks?: ProgramHooks; pluginContext?: PluginContext; - isFrameworkMode ?: boolean; + isFrameworkMode?: boolean; } export interface ProgramHookConfig { @@ -102,12 +104,7 @@ export class ProgramVisitor extends AbstractVisitor { prefixName: string, extensionName: string ): void { - debugDumpAstNode( - script, - getDumpFileName(this.state, prefixName, undefined, name), - cachePath, - extensionName - ); + debugDumpAstNode(script, getDumpFileName(this.state, prefixName, undefined, name), cachePath, extensionName); } private visitLegacyInExternalSource(program: arkts.Program, externalSourceName: string): void { @@ -115,7 +112,9 @@ export class ProgramVisitor extends AbstractVisitor { transformer.isExternal = !!externalSourceName; transformer.externalSourceName = externalSourceName; transformer.program = program; - transformer.visitor(program.ast); + const newScript = transformer.visitor(program.ast) as arkts.ETSModule; + program?.setAst(newScript) + arkts.setAllParents(newScript); } private visitNonLegacyInExternalSource( @@ -125,11 +124,9 @@ export class ProgramVisitor extends AbstractVisitor { cachePath?: string ): void { const extensionName: string = program.fileNameWithExtension; - this.dumpExternalSource(currProgram.ast, name, cachePath, 'ORI', extensionName); - const script = this.visitor(currProgram.ast, currProgram, name); - if (script) { - this.dumpExternalSource(script, name, cachePath, this.pluginName, extensionName); - } + this.dumpExternalSource(currProgram.ast, name, `${cachePath}/BEFORE`, this.pluginName, extensionName); + const newScript = this.visitor(currProgram.ast, currProgram, name); + this.dumpExternalSource(newScript, name, `${cachePath}/AFTER`, this.pluginName, extensionName); } private visitNextProgramInQueue( @@ -154,10 +151,7 @@ export class ProgramVisitor extends AbstractVisitor { return false; } - private visitExternalSources( - program: arkts.Program, - programQueue: arkts.Program[] - ): void { + private visitExternalSources(program: arkts.Program, programQueue: arkts.Program[]): void { const visited = new Set(); const queue: arkts.Program[] = programQueue; while (queue.length > 0) { @@ -168,8 +162,13 @@ export class ProgramVisitor extends AbstractVisitor { if (currProgram.peer !== program.peer) { const name: string = this.filenames.get(currProgram.peer)!; const cachePath: string | undefined = this.pluginContext?.getProjectConfig()?.cachePath; - if (this.pluginContext && 'getFileManager' in this.pluginContext && this.state === arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED && - this.pluginName === 'uiTransform' && this.isLegacyFile(currProgram.absoluteName)) { + if ( + this.pluginContext && + 'getFileManager' in this.pluginContext && + this.state === arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED && + this.pluginName === 'uiTransform' && + this.isLegacyFile(currProgram.absoluteName) + ) { this.visitLegacyInExternalSource(currProgram, name); } else { this.visitNonLegacyInExternalSource(program, currProgram, name, cachePath); @@ -202,15 +201,16 @@ export class ProgramVisitor extends AbstractVisitor { node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string - ): void { + ): arkts.ETSModule { let script: arkts.ETSModule = node as arkts.ETSModule; const preVisitors = hook?.pre?.visitors ?? []; for (const transformer of preVisitors) { - this.visitTransformer(transformer, script, externalSourceName, program); + script = this.visitTransformer(transformer, script, externalSourceName, program); if (!this.hooks?.external?.pre?.resetAfter) { transformer.reset(); } } + return script } private postVisitor( @@ -218,15 +218,16 @@ export class ProgramVisitor extends AbstractVisitor { node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string - ): void { + ): arkts.ETSModule { let script: arkts.ETSModule = node as arkts.ETSModule; const postVisitors = hook?.post?.visitors ?? []; for (const transformer of postVisitors) { - this.visitTransformer(transformer, script, externalSourceName, program); + script = this.visitTransformer(transformer, script, externalSourceName, program); if (!this.hooks?.external?.pre?.resetAfter) { transformer.reset(); } } + return script } visitor(node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string): arkts.ETSModule { @@ -244,11 +245,10 @@ export class ProgramVisitor extends AbstractVisitor { // pre-run visitors hook = isExternal ? this.hooks?.external : this.hooks?.source; - this.preVisitor(hook, node, program, externalSourceName); + script = this.preVisitor(hook, script, program, externalSourceName); for (const transformer of this.visitors) { - this.visitTransformer(transformer, script, externalSourceName, program); - arkts.setAllParents(script); + script = this.visitTransformer(transformer, script, externalSourceName, program); if (!transformer.isExternal) { debugDumpAstNode( script, @@ -262,7 +262,7 @@ export class ProgramVisitor extends AbstractVisitor { // post-run visitors hook = isExternal ? this.hooks?.external : this.hooks?.source; - this.postVisitor(hook, node, program, externalSourceName); + script = this.postVisitor(hook, script, program, externalSourceName); return script; } @@ -282,13 +282,13 @@ export class ProgramVisitor extends AbstractVisitor { arkts.setAllParents(newScript); importStorage.update(); transformer.reset(); - return newScript; + return program!.ast as arkts.ETSModule; } } export class CanSkipPhasesCache { static resultCache = new Map() - + static check(program: arkts.Program) { if (!CanSkipPhasesCache.resultCache.has(program)) { const result = arkts.global.es2panda._ProgramCanSkipPhases(arkts.global.context, program.peer); diff --git a/ui2abc/arkui-plugins/common/safe-types.ts b/ui2abc/arkui-plugins/common/safe-types.ts index 09ccd909234f3b704687e8653ab5b929eb5bd806..5b60945bc1152faa3256451bee776fc72bd1f764 100644 --- a/ui2abc/arkui-plugins/common/safe-types.ts +++ b/ui2abc/arkui-plugins/common/safe-types.ts @@ -26,10 +26,10 @@ export type PartialNested = { [P in keyof T]?: T[P] extends readonly any[] | any[] ? PartialArray : T[P] extends arkts.AstNode - ? PartialAstNode - : T[P] extends object - ? PartialObject - : PartialPrimitive; + ? PartialAstNode + : T[P] extends object + ? PartialObject + : PartialPrimitive; }; type NestedKey = { diff --git a/ui2abc/arkui-plugins/interop-plugins/emit_transformer.ts b/ui2abc/arkui-plugins/interop-plugins/emit_transformer.ts index f6557556dbc770aeb5044fcb509095eb4aced3d2..87f96f1027f63bc543849ae522a82cbf293f0311 100644 --- a/ui2abc/arkui-plugins/interop-plugins/emit_transformer.ts +++ b/ui2abc/arkui-plugins/interop-plugins/emit_transformer.ts @@ -66,7 +66,8 @@ export class EmitTransformer extends AbstractVisitor { value ? property.value : arkts.factory.createStringLiteral(node.key.name), property.typeAnnotation, property.modifiers, - false + false, + property.annotations ) ]); } @@ -100,7 +101,8 @@ export class EmitTransformer extends AbstractVisitor { arkts.factory.createStringLiteral(aliasValue), allowOverrideProp.typeAnnotation, allowOverrideProp.modifiers, - false + false, + allowOverrideProp.annotations ) ]); } else { @@ -111,7 +113,8 @@ export class EmitTransformer extends AbstractVisitor { aliasProp.value, aliasProp.typeAnnotation, aliasProp.modifiers, - false + false, + aliasProp.annotations ) ]); } diff --git a/ui2abc/arkui-plugins/interop-plugins/index.ts b/ui2abc/arkui-plugins/interop-plugins/index.ts index 4f1ee8c98074d47ff110fef87f4a1ca4f05137d3..34e24f07ebdb22a28a764f9db7c5d39d3e443582 100644 --- a/ui2abc/arkui-plugins/interop-plugins/index.ts +++ b/ui2abc/arkui-plugins/interop-plugins/index.ts @@ -21,24 +21,20 @@ import { EmitTransformer } from './emit_transformer'; import { ProgramVisitor } from '../common/program-visitor'; import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../common/predefines'; import { debugLog } from '../common/debug'; -import { Plugins, PluginContext } from '../common/plugin-context'; -import { captureProgramSkipperToPluginContext, ProgramSkipper } from "../common/program-skipper"; +import { PluginContext, Plugins } from '../common/plugin-context'; +import { ProgramSkipper } from "../common/program-skipper"; -export function init(): Plugins { +export function interopTransform():Plugins { return { name: 'interop-plugin', parsed: parsedTransform, checked: checkedTransform, - clean() { + clean(): void { ProgramSkipper.clear(); }, }; } -export function interopTransform(): Plugins { - return init(); -} - function parsedTransform(this: PluginContext): arkts.ETSModule | undefined { let script: arkts.ETSModule | undefined; debugLog('interopTransform:parsed'); @@ -93,7 +89,7 @@ function checkedTransform(this: PluginContext): arkts.ETSModule | undefined { program = programVisitor.programVisitor(program); script = program.ast; arkts.recheckSubtree(script); - this.setArkTSAst(script as arkts.ETSModule); + this.setArkTSAst(script as arkts.ETSModule); debugLog('interopTransform:checked exit'); return script as arkts.ETSModule; } @@ -101,3 +97,8 @@ function checkedTransform(this: PluginContext): arkts.ETSModule | undefined { debugLog('interopTransform:checked exit with no transform'); return undefined; } + +// required for es2panda +export function init(): Plugins { + return interopTransform(); +} diff --git a/ui2abc/arkui-plugins/jest-test.config.js b/ui2abc/arkui-plugins/jest-test.config.js index 650585939d9625fe4cb1b7f8c69af16844197fea..d3f124ac5b3386a71f09d50ec32f6f6b08b9d4f5 100644 --- a/ui2abc/arkui-plugins/jest-test.config.js +++ b/ui2abc/arkui-plugins/jest-test.config.js @@ -56,5 +56,9 @@ module.exports = { PANDA_SDK_PATH: pandaSdkPath, API_PATH: apiPath, KIT_PATH: kitPath, + UI_CACHE_ENABLED: true, + UI_UPDATE_ENABLED: true, + MEMO_CACHE_ENABLED: true, + MEMO_UPDATE_ENABLED: true, }, }; diff --git a/ui2abc/arkui-plugins/memo-plugins/function-transformer.ts b/ui2abc/arkui-plugins/memo-plugins/function-transformer.ts index 90aa67f521c931ad79117be97882c082b1f78c64..b234c8a7cb4bd0b12707a7b7ddf45700c415af95 100644 --- a/ui2abc/arkui-plugins/memo-plugins/function-transformer.ts +++ b/ui2abc/arkui-plugins/memo-plugins/function-transformer.ts @@ -63,6 +63,8 @@ import { prepareRewriteScriptFunctionParameters, prepareRewriteScriptFunctionReturnType } from './memo-cache-factory'; +import { NodeCacheNames } from '../common/predefines'; +import { NodeCacheFactory } from '../common/node-cache'; interface ScopeInfo extends MemoInfo { regardAsSameScope?: boolean; @@ -260,7 +262,7 @@ export class FunctionTransformer extends AbstractVisitor { scriptFunction.getSignaturePointer?.() ?? undefined, scriptFunction.getPreferredReturnTypePointer?.() ?? undefined ); - } + } updateScriptFunctionFromInterfaceGetterSetter(node: arkts.ScriptFunction): arkts.ScriptFunction { const _isGetter = isScriptFunctionFromGetter(node); @@ -698,7 +700,7 @@ export class FunctionTransformer extends AbstractVisitor { node.isMethod, node.isComputed ); - } + } private updateThisAttributeAssignment( node: arkts.AssignmentExpression, @@ -729,9 +731,14 @@ export class FunctionTransformer extends AbstractVisitor { } private visitorWithCache(beforeChildren: arkts.AstNode): arkts.AstNode { + const _memoCache = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO); + // TBD(Upgrade): Lead to incorrect memorization + // if (!_memoCache.shouldUpdate(beforeChildren)) { + // return beforeChildren; + // } const node = this.visitEachChild(beforeChildren); - if (arkts.MemoNodeCache.getInstance().has(node)) { - const value = arkts.MemoNodeCache.getInstance().get(node)!; + if (_memoCache.has(node)) { + const value = _memoCache.get(node)!; if (rewriteByType.has(value.type)) { this.modified = true; const metadata: CachedMetadata = { ...value.metadata, internalsTransformer: this.internalsTransformer }; diff --git a/ui2abc/arkui-plugins/memo-plugins/index.ts b/ui2abc/arkui-plugins/memo-plugins/index.ts index c2b110d1e34cc95878255bdcf4c39c51c1784d86..a41403ea5c0beeafa306ad6cddd9cef0d2ed70e2 100644 --- a/ui2abc/arkui-plugins/memo-plugins/index.ts +++ b/ui2abc/arkui-plugins/memo-plugins/index.ts @@ -20,15 +20,16 @@ import { PositionalIdTracker } from './utils'; import { ReturnTransformer } from './return-transformer'; import { ParameterTransformer } from './parameter-transformer'; import { CanSkipPhasesCache, ProgramVisitor } from '../common/program-visitor'; -import { EXTERNAL_SOURCE_PREFIX_NAMES, EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK } from '../common/predefines'; -import { debugDumpAstNode, debugLog, getDumpFileName } from '../common/debug'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK, NodeCacheNames } from '../common/predefines'; +import { Debugger, debugLog } from '../common/debug'; import { SignatureTransformer } from './signature-transformer'; import { InternalsTransformer } from './internal-transformer'; import { ProgramSkipper } from "../common/program-skipper"; +import { NodeCacheFactory } from '../common/node-cache'; import * as memo from '@ohos/arkts-compiler-infra'; import { disableMemoNodeCache, useImprovedPlugin } from '../common/use-improved-memo-plugin'; -export function init(): Plugins { +export function unmemoizeTransform(): Plugins { return { name: 'memo-plugin', parsed: parsedTransform, @@ -39,37 +40,19 @@ export function init(): Plugins { }; } -function pluginInit(context: PluginContext) { - arkts.extendPluginContext(context) - if (!useImprovedPlugin) { - return - } - arkts.MemoNodeCache.disableMemoNodeCache = disableMemoNodeCache; - memo.initPlugin(context) - memo.memoPluginOptionsFromContext(context).skipDiagnostics = true; -} - -function parsedTransform(this: PluginContext) { - pluginInit(this) - if (!useImprovedPlugin) { - return - } - memo.parsedTransform(this) -} - function checkedTransform(this: PluginContext): arkts.ETSModule | undefined { - console.log('[MEMO PLUGIN] AFTER CHECKED ENTER'); + Debugger.getInstance().phasesDebugLog('[MEMO PLUGIN] AFTER CHECKED ENTER'); arkts.Performance.getInstance().memoryTrackerReset(); arkts.Performance.getInstance().startMemRecord('Node:UIPlugin:Memo-AfterCheck'); const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; - if (!!contextPtr) { + const isCoding = this.isCoding?.() ?? false; + if (!isCoding && !!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; let script = program.ast as arkts.ETSModule; const isFrameworkMode = !!this.getProjectConfig()?.frameworkMode; - const canSkipPhases = !isFrameworkMode && CanSkipPhasesCache.check(program); - arkts.Performance.getInstance().createEvent('memo-checked'); + arkts.Performance.getInstance().createEvent('memo-checked'); if (useImprovedPlugin) { program = improvedCheckedProgramVisit(program, this, canSkipPhases, isFrameworkMode); } else { @@ -78,7 +61,6 @@ function checkedTransform(this: PluginContext): arkts.ETSModule | undefined { script = program.ast as arkts.ETSModule; arkts.Performance.getInstance().stopEvent('memo-checked', true); - arkts.Performance.getInstance().memoryTrackerGetDelta('UIPlugin:Memo-AfterCheck'); arkts.Performance.getInstance().memoryTrackerReset(); arkts.Performance.getInstance().stopMemRecord('Node:UIPlugin:Memo-AfterCheck'); @@ -90,29 +72,13 @@ function checkedTransform(this: PluginContext): arkts.ETSModule | undefined { arkts.Performance.getInstance().memoryTrackerGetDelta('ArkTS:Recheck'); arkts.Performance.getInstance().stopMemRecord('Node:ArkTS:Recheck'); arkts.Performance.getInstance().memoryTrackerPrintCurrent('UIPlugin:End'); - console.log('[MEMO PLUGIN] AFTER CHECKED EXIT'); + Debugger.getInstance().phasesDebugLog('[MEMO PLUGIN] AFTER CHECKED EXIT'); return script; } - console.log('[MEMO PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); + Debugger.getInstance().phasesDebugLog('[MEMO PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); return undefined; } -function improvedCheckedProgramVisit( - program: arkts.Program, - pluginContext: PluginContext, - canSkipPhases: boolean = false, - isFrameworkMode: boolean = false -): arkts.Program { - if (canSkipPhases) { - debugLog('[SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); - } else { - debugLog('[CANT SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); - memo.checkedTransform(pluginContext) - arkts.MemoNodeCache.getInstance().clear(); - } - return program; -} - function checkedProgramVisit( program: arkts.Program, pluginContext: PluginContext, @@ -137,13 +103,13 @@ function checkedProgramVisit( returnTransformer, signatureTransformer, internalsTransformer, - useCache: arkts.MemoNodeCache.getInstance().isCollected(), + useCache: NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).isCollected(), }); const skipPrefixNames = isFrameworkMode ? EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK : EXTERNAL_SOURCE_PREFIX_NAMES; const programVisitor = new ProgramVisitor({ - pluginName: 'memo-plugin', + pluginName: unmemoizeTransform.name, state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, visitors: [functionTransformer], skipPrefixNames, @@ -151,7 +117,46 @@ function checkedProgramVisit( isFrameworkMode }); program = programVisitor.programVisitor(program); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).clear(); + } + return program; +} + +function improvedCheckedProgramVisit( + program: arkts.Program, + pluginContext: PluginContext, + canSkipPhases: boolean = false, + isFrameworkMode: boolean = false +): arkts.Program { + if (canSkipPhases) { + debugLog('[SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); + } else { + debugLog('[CANT SKIP PHASE] phase: memo-checked, moduleName: ', program.moduleName); + memo.checkedTransform(pluginContext) arkts.MemoNodeCache.getInstance().clear(); } return program; } + +function pluginInit(context: PluginContext) { + arkts.extendPluginContext(context) + if (!useImprovedPlugin) { + return + } + arkts.MemoNodeCache.disableMemoNodeCache = disableMemoNodeCache; + memo.initPlugin(context) + memo.memoPluginOptionsFromContext(context).skipDiagnostics = true; +} + +function parsedTransform(this: PluginContext) { + pluginInit(this) + if (!useImprovedPlugin) { + return + } + memo.parsedTransform(this) +} + +// required for es2panda +export function init(): Plugins { + return unmemoizeTransform(); +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/memo-plugins/memo-cache-factory.ts b/ui2abc/arkui-plugins/memo-plugins/memo-cache-factory.ts index b24c0e8f2ebed7ba01b3e5bc9623433d45c74bd0..3919360183ed251894ceb59d7f4631ba99a87617 100644 --- a/ui2abc/arkui-plugins/memo-plugins/memo-cache-factory.ts +++ b/ui2abc/arkui-plugins/memo-plugins/memo-cache-factory.ts @@ -14,6 +14,8 @@ */ import * as arkts from '@koalaui/libarkts'; +import { BuiltInNames } from '../common/predefines'; +import { isArrowFunctionAsValue } from '../collectors/memo-collectors/utils'; import { factory } from './memo-factory'; import { filterMemoSkipParams, @@ -29,8 +31,7 @@ import { PositionalIdTracker, } from './utils'; import { InternalsTransformer } from './internal-transformer'; -import { GenSymPrefix } from '../common/predefines'; -import { AstNodeCacheValueMetadata } from 'common/node-cache'; +import { AstNodeCacheValueMetadata } from '../common/node-cache'; export interface CachedMetadata extends AstNodeCacheValueMetadata { internalsTransformer?: InternalsTransformer; @@ -38,9 +39,12 @@ export interface CachedMetadata extends AstNodeCacheValueMetadata { export class RewriteFactory { static rewriteTsAsExpression(node: arkts.TSAsExpression, metadata?: CachedMetadata): arkts.TSAsExpression { + const newExpr = !!node.expr && arkts.isArrowFunctionExpression(node.expr) + ? RewriteFactory.rewriteArrowFunction(node.expr) + : node.expr; return arkts.factory.updateTSAsExpression( node, - node.expr, + newExpr, RewriteFactory.rewriteType(node.typeAnnotation, metadata), node.isConst ); @@ -129,24 +133,22 @@ export class RewriteFactory { if (!node.typeAnnotation && !node.initializer) { return node; } - node.setTypeAnnotation(RewriteFactory.rewriteType(node.typeAnnotation, metadata)); - return arkts.factory.updateETSParameterExpression(node, node.ident, node.isOptional, node.initializer, node.annotations); + node.setTypeAnnotation(RewriteFactory.rewriteType(node.typeAnnotation, metadata)); + return node; } static rewriteProperty(node: arkts.Property, metadata?: CachedMetadata): arkts.Property { - if (!node.value || !arkts.isArrowFunctionExpression(node.value)) { + const value: arkts.Expression | undefined = node.value; + if (!value) { return node; } - const newValue = RewriteFactory.rewriteArrowFunction(node.value, metadata); - return arkts.factory.updateProperty( - node, - node.kind, - node.key, - newValue, - node.isMethod, - node.isComputed - ); - } + if (arkts.isArrowFunctionExpression(value)) { + node.setValue(RewriteFactory.rewriteArrowFunction(value, metadata)); + } else if (isArrowFunctionAsValue(value)) { + node.setValue(RewriteFactory.rewriteTsAsExpression(value, metadata)); + } + return node; + } static rewriteClassProperty(node: arkts.ClassProperty, metadata?: CachedMetadata): arkts.ClassProperty { const newType = !!node.typeAnnotation ? RewriteFactory.rewriteType(node.typeAnnotation, metadata) : undefined; @@ -322,7 +324,10 @@ 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/ui2abc/arkui-plugins/memo-plugins/parameter-transformer.ts b/ui2abc/arkui-plugins/memo-plugins/parameter-transformer.ts index 64d97566ce1c017308552b02f45089ce9b45e055..a3e9cb220bda903dc7d34b57cbbc6d20c51790e2 100644 --- a/ui2abc/arkui-plugins/memo-plugins/parameter-transformer.ts +++ b/ui2abc/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; } @@ -243,7 +243,7 @@ export class ParameterTransformer extends AbstractVisitor { return this.updateParamReDeclare(declarator, memoInfo); } if (!!declarator.init && arkts.isIdentifier(declarator.init)) { - const decl = arkts.getPeerDecl(declarator.init.originalPeer); + const decl = arkts.getPeerIdentifierDecl(declarator.init.originalPeer); if (decl && this.rewriteIdentifiers?.has(decl.peer)) { return arkts.factory.updateVariableDeclarator( declarator, @@ -280,7 +280,7 @@ export class ParameterTransformer extends AbstractVisitor { return this.updateVariableReDeclarationFromParam(beforeChildren); } if (arkts.isCallExpression(beforeChildren) && arkts.isIdentifier(beforeChildren.callee)) { - const decl = arkts.getPeerDecl(beforeChildren.callee.originalPeer); + const decl = arkts.getPeerIdentifierDecl(beforeChildren.callee.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) @@ -294,7 +294,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/ui2abc/arkui-plugins/memo-plugins/signature-transformer.ts b/ui2abc/arkui-plugins/memo-plugins/signature-transformer.ts index bb605611bf4ee3f5b1e820e62e5a14153a98e5ee..38997861ae8c52738dc1b191e2c79038d152047d 100644 --- a/ui2abc/arkui-plugins/memo-plugins/signature-transformer.ts +++ b/ui2abc/arkui-plugins/memo-plugins/signature-transformer.ts @@ -110,7 +110,7 @@ export class SignatureTransformer extends AbstractVisitor { throw 'Invalid @memo usage'; } const expr = node.part.name; - const decl = arkts.getDecl(expr); + const decl = arkts.getPeerIdentifierDecl(expr.peer); if (!decl || !arkts.isTSTypeAliasDeclaration(decl)) { return node as any as T; } diff --git a/ui2abc/arkui-plugins/memo-plugins/utils.ts b/ui2abc/arkui-plugins/memo-plugins/utils.ts index 8888e16a8a3ebcf6a5fc52ab009a74062e821c6c..6c4f479475c4a92f0a7771cb0a2a0a17985a021e 100644 --- a/ui2abc/arkui-plugins/memo-plugins/utils.ts +++ b/ui2abc/arkui-plugins/memo-plugins/utils.ts @@ -23,6 +23,7 @@ export enum RuntimeNames { __KEY = '__key', ANNOTATION_BUILDER = 'Builder', ANNOTATION = 'memo', + ANNOTATION_UI = 'Memo', ANNOTATION_ENTRY = 'memo_entry', ANNOTATION_INTRINSIC = 'memo_intrinsic', ANNOTATION_STABLE = 'memo_stable', @@ -136,7 +137,7 @@ export type MemoAstNode = export function hasMemoAnnotation(node: T): boolean { return node.annotations.some((it) => - isMemoAnnotation(it, [RuntimeNames.ANNOTATION, RuntimeNames.ANNOTATION_BUILDER]) + isMemoAnnotation(it, [RuntimeNames.ANNOTATION, RuntimeNames.ANNOTATION_BUILDER, RuntimeNames.ANNOTATION_UI]) ); } @@ -160,8 +161,8 @@ export function hasMemoSkipAnnotation(node: arkts.ETSParameterExpression): boole export function removeMemoAnnotation(node: T): T { const newAnnotations: arkts.AnnotationUsage[] = node.annotations.filter( - (it) => !isMemoAnnotation(it, RuntimeNames.ANNOTATION) && !isMemoAnnotation(it, RuntimeNames.ANNOTATION_STABLE) - ); + (it) => !isMemoAnnotation(it, RuntimeNames.ANNOTATION) && !isMemoAnnotation(it, RuntimeNames.ANNOTATION_STABLE) && + !isMemoAnnotation(it, RuntimeNames.ANNOTATION_UI)); if (arkts.isETSParameterExpression(node)) { node.setAnnotations(newAnnotations); return node; @@ -186,6 +187,7 @@ function isIfStatementWithSyntheticReturn(node: arkts.AstNode): boolean { node.test.object.name === RuntimeNames.SCOPE && arkts.isIdentifier(node.test.property) && node.test.property.name === RuntimeNames.INTERNAL_VALUE_OK && + !!node.consequent && (arkts.isBlockStatement(node.consequent) || arkts.isReturnStatement(node.consequent)) ); } @@ -464,7 +466,7 @@ export function findMemoFromTypeAnnotation(typeAnnotation: arkts.AstNode | undef return false; } if (arkts.isETSTypeReference(typeAnnotation) && !!typeAnnotation.part && !!typeAnnotation.part.name) { - let decl: arkts.AstNode | undefined = arkts.getDecl(typeAnnotation.part.name); + let decl: arkts.AstNode | undefined = arkts.getPeerIdentifierDecl(typeAnnotation.part.name.peer); if (!decl || !arkts.isTSTypeAliasDeclaration(decl)) { return false; } @@ -490,7 +492,7 @@ export function findReturnTypeFromTypeAnnotation( return undefined; } if (arkts.isETSTypeReference(typeAnnotation) && !!typeAnnotation.part && !!typeAnnotation.part.name) { - let decl: arkts.AstNode | undefined = arkts.getDecl(typeAnnotation.part.name); + let decl: arkts.AstNode | undefined = arkts.getPeerIdentifierDecl(typeAnnotation.part.name.peer); if (!!decl && arkts.isTSTypeAliasDeclaration(decl)) { return findReturnTypeFromTypeAnnotation(decl.typeAnnotation); } @@ -665,8 +667,8 @@ export function isScriptFunctionFromInterfaceGetterSetter(node: arkts.ScriptFunc if (!methodDef || !arkts.isMethodDefinition(methodDef)) { return false; } - const isGetterSetter = methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET - || methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET; + const isGetterSetter = methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET || + methodDef.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET; if (!isGetterSetter) { return false; } diff --git a/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_decorator_property_type.ets b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_decorator_property_type.ets new file mode 100644 index 0000000000000000000000000000000000000000..98257a6aecbf7d558f00af264568570adc34c70b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_decorator_property_type.ets @@ -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 { Entry, Component, Column, Text, ComponentV2, Builder, BuilderParam } from '@ohos.arkui.component' +import { Prop, State, Local, Event, Provide, Provider, Consumer, Param, Link, Consume, Once, Require } from + "@ohos.arkui.stateManagement"; + +//#1 +@Builder +function testBuilder() { + Text("testBuilder").fontSize(30); +} + +@Entry +@ComponentV2 +struct V2ComponentMemberTypeCheck02 { + // 以下的变量会进行类型检查,The property 'local_value' must specify a type. + @Local local_value = "hello" + @BuilderParam builder_value = testBuilder + @Once @Param @Require param_value = "hello" + @Param @Require param_value1 = "hello" + @Once @Param param_value2 = "hello" + @Param param_value3 = "hello" + @Event event_value = "hello" + @Provider() provide_value = "hello" + @Consumer() consumer_value = "hello" + + build() { + Text("V2Component member type check"); + } +} +//#2 +@Entry +@Component +struct testOne { + @Consume consumeOne = 'consumeOne'; + @State stateOne = 'stateOne'; + @Provide provideOne = 'provideOne'; + @Prop propOne = "propOne"; + @Require requireOne = "requireOne"; + @Link linkOne = "linkOne"; + + build() { + Column() { + Text(this.consumeOne); + } + } +} +//#3 +@Entry +@ComponentV2 +struct testOne { + @Consumer('') consumeOne = 'consumeOne'; + @Local stateOne = 'stateOne'; + @Provider('') provideOne = 'provideOne'; + @Param propOne; + @Require requireOne; // no error report, it's OK + @BuilderParam builderParamOne; + + build() { + Column() { + Text(this.consumeOne); + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_property_modifiers.ets b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_property_modifiers.ets new file mode 100644 index 0000000000000000000000000000000000000000..ba41957b7bb91f111ae92773f21c92dcf58618cc --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/check_property_modifiers.ets @@ -0,0 +1,79 @@ +/* + * 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 { Entry, Component, Column, Text } from '@ohos.arkui.component' +import { Consume, State, Provide, StoragePropRef, StorageLink, LocalStoragePropRef, LocalStorageLink } from "@ohos.arkui.stateManagement"; + +//#1 +@Entry +@Component +struct Child1struct03 { + @StoragePropRef("a") public local_prop_value: string = "hello"; + @LocalStorageLink("b") public local_link_value: string = "hello"; + @StorageLink("c") public storage_link_value: string = "hello"; + @LocalStoragePropRef("a") public consume_value: string; + + build() {} +} +//#2 +@Entry +@Component +struct testOne { + @Consume public consumeOne: string = 'consumeOne'; + @State public stateOne: string = 'stateOne'; + @Provide public provideOne: string = 'provideOne'; + @StoragePropRef('storageOne') public storagePropOne: string = 'storagePropOne'; + @StorageLink('storageOne') public storageLinkOne: string = 'storageLinkOne'; + @LocalStoragePropRef('storageTwo') public localStoragePropOne: string = 'localStoragePropOne'; + @LocalStorageLink('storageTwo') public localStorageLinkOne: string = 'localStorageLinkOne'; + + build() { + Column() { + Text(this.consumeOne); + } + } +} +//#3 +@Entry +@Component +struct testOne { + @Consume consumeOne: string = 'consumeOne'; + @State public stateOne: string = 'stateOne'; + @Provide public provideOne: string = 'provideOne'; + @StoragePropRef('storageOne') storagePropOne: string = 'storagePropOne'; + @StorageLink('storageOne') storageLinkOne: string = 'storageLinkOne'; + + build() { + Column() { + Text(this.consumeOne); + } + } +} +//#4 +@Entry +@Component +struct testOne { + @Consume public consumeOne: string = 'consumeOne'; + @State public stateOne: string = 'stateOne'; + @Provide public provideOne: string = 'provideOne'; + @LocalStoragePropRef('storageTwo') public localStoragePropOne: string = 'localStoragePropOne'; + @LocalStorageLink('storageTwo') public localStorageLinkOne: string = 'localStorageLinkOne'; + + build() { + Column() { + Text(this.consumeOne); + } + } +} diff --git a/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets index 76b8150735a73f4c837ce9da39f669ca01e07c3e..a4410ee30606a54461990c4440d5d34c1c00cfb8 100755 --- a/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets +++ b/ui2abc/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets @@ -14,7 +14,7 @@ */ import { Text, Column, Component, Entry, Button, ClickEvent } from "@ohos.arkui.component" -import { State, Link, Prop } from "@ohos.arkui.stateManagement" +import { State, Link, PropRef } from "@ohos.arkui.stateManagement" import hilog from '@ohos.hilog' @Entry @@ -43,7 +43,7 @@ struct MyStateSample { @Component struct Child { @Link linkVar: string; - @Prop propVar: string = "Prop"; + @PropRef propVar: string = "Prop"; changeValue1() { this.linkVar+="!!" diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/condition-scope/if-break-in-nested-content.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/condition-scope/if-break-in-nested-content.ets index 29482e82f8b52ab0a6c6b1f281d5c3ac8a2890f8..4f522cc1a49eb7fdd523d77bea16a1bdae07e692 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/condition-scope/if-break-in-nested-content.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/condition-scope/if-break-in-nested-content.ets @@ -1,18 +1,3 @@ -/* - * 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 { Component, Column, Text } from "@ohos.arkui.component"; import hilog from "@ohos.hilog"; diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/custom-builder.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/custom-builder.ets new file mode 100644 index 0000000000000000000000000000000000000000..8875871c6c3f3ec3c8b8a2e06aae0f8cb7000eba --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/custom-builder.ets @@ -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 { Text, Column, Component, Builder, ListItemGroup, CustomBuilder } from "@ohos.arkui.component" + +@Component +struct MyStateSample { + @Builder + itemHead(text: string) { + Text(text) + .fontSize(20) + .backgroundColor(0xAABBCC) + } + + @Builder + itemFoot(num: number) { + Text('Foot') + .fontSize(16) + .backgroundColor(0xAABBCC) + } + + build() { + Column() { + ListItemGroup({ + header: () => { this.itemHead('Head') }, + footer: () => { this.itemFoot(100) } as CustomBuilder + }) {} + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/multi-component-builder.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/multi-component-builder.ets new file mode 100644 index 0000000000000000000000000000000000000000..34a8585d911c93d0ea2b4adabcb1b4f819aa4b61 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/multi-component-builder.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component } from "arkui.component.customComponent"; +import { FakeComponentA, FakeComponentB, FakeComponentC } from "./utils/fake-multi-component"; + +@Entry +@Component +struct A { + build() { + FakeComponentA("fake-component"); + FakeComponentB({}); + FakeComponentC() { + + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/overload-component-builder.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/overload-component-builder.ets new file mode 100644 index 0000000000000000000000000000000000000000..2a4e37dd12c399513b524286d685af089f98b28a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/overload-component-builder.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component } from "arkui.component.customComponent"; +import { FakeComponent } from "./utils/fake-overload-component"; + +@Entry +@Component +struct A { + build() { + FakeComponent("fake-component"); + FakeComponent({}); + FakeComponent() { + + } + } +} diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/simple-component.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/simple-component.ets new file mode 100644 index 0000000000000000000000000000000000000000..ed5ff7d2472e47ac7a720d3b952f09f095fa06ea --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/simple-component.ets @@ -0,0 +1,23 @@ +/* + * 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 { Memo } from "arkui.incremental.annotation" +import { Column, ColumnAttribute } from "arkui.component.column" + +class MyStateSample { + @Memo build() { + Column(undefined) {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-multi-component.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-multi-component.ets new file mode 100644 index 0000000000000000000000000000000000000000..84586380608a29e3a4036d975460d75948eb97ba --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-multi-component.ets @@ -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 { ComponentBuilder } from "arkui.component.builder" +import { Memo } from "arkui.incremental.annotation" + +interface FakeOptions { + str?: string; +} + +interface FakeComponentAAttribute { + +} + +interface FakeComponentBAttribute { + +} + +interface FakeComponentCAttribute { + +} + +@Memo +@ComponentBuilder +export declare function FakeComponentA( + str: string, + @Memo + content_?: () => void, +): FakeComponentAAttribute; + +@Memo +@ComponentBuilder +export declare function FakeComponentB( + options?: FakeOptions, + @Memo + content_?: () => void, +): FakeComponentBAttribute; + +@Memo +@ComponentBuilder +export declare function FakeComponentC( + @Memo + content_?: () => void, +): FakeComponentCAttribute; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-overload-component.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-overload-component.ets new file mode 100644 index 0000000000000000000000000000000000000000..67457a4952ccb7d0f2e4726640ef27f5c32c5101 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/inner-component/utils/fake-overload-component.ets @@ -0,0 +1,48 @@ +/* + * 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 { ComponentBuilder } from "arkui.component.builder" +import { Memo } from "arkui.incremental.annotation" + +interface FakeOptions { + str?: string; +} + +interface FakeComponentAttribute { + +} + +@Memo +@ComponentBuilder +export declare function FakeComponent( + str: string, + @Memo + content_?: () => void, +): FakeComponentAttribute; + +@Memo +@ComponentBuilder +export declare function FakeComponent( + options?: FakeOptions, + @Memo + content_?: () => void, +): FakeComponentAttribute; + +@Memo +@ComponentBuilder +export declare function FakeComponent( + @Memo + content_?: () => void, +): FakeComponentAttribute; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/style-with-receiver.ets b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/style-with-receiver.ets index 40aa74d66d724df6488eef9d6d9591b1df6cb3c5..6746aa2b69de34dea95d6c2fde27129f5bf16c62 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/style-with-receiver.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/builder-lambda/style-with-receiver.ets @@ -13,17 +13,17 @@ * limitations under the License. */ -import { memo } from "@ohos.arkui.stateManagement" // should be insert by ui-plugins -import { Text, TextAttribute, Column, Component} from "@ohos.arkui.component" +import { Memo } from "@ohos.arkui.stateManagement" +import { Text, TextAttribute, Column, Component } from "@ohos.arkui.component" import hilog from '@ohos.hilog' -@memo function cardStyle(this: TextAttribute, num: number, str: string): this { +@Memo function cardStyle(this: TextAttribute, num: number, str: string): this { this.fontSize(num); this.backgroundColor(str); return this; } -@memo function style22(this: TextAttribute): this { +@Memo function style22(this: TextAttribute): this { this.fontWeight(700); return this; } diff --git a/ui2abc/arkui-plugins/test/demo/mock/decorators/builder/global-builder.ets b/ui2abc/arkui-plugins/test/demo/mock/decorators/builder/global-builder.ets index bba1e6ee0cd7da5ac40d1cefae611358c19e9138..5175f1a924796482c5d2bfc3ba338429802b8f4d 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/decorators/builder/global-builder.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/decorators/builder/global-builder.ets @@ -30,12 +30,22 @@ class Tmp { } } +interface Person { + age?: number; +} + +@Builder function globalBuilder(param: Person) { + Text('globalBuilder') +} + @Component struct BuilderDemo { build() { Row() { showTextBuilder() overBuilder({ paramA1: 'Hello' }) + globalBuilder({ age: 18 }) + globalBuilder({}) } } } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/decorators/regular/readonly-regular.ets b/ui2abc/arkui-plugins/test/demo/mock/decorators/regular/readonly-regular.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f70b48a96de789b1dcd21a6497525b84d9db1ae --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/decorators/regular/readonly-regular.ets @@ -0,0 +1,23 @@ +/* + * 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 { ComponentV2 } from "@ohos.arkui.component" + +@ComponentV2 +struct Child { + private readonly readOnlyParam: number = 0; + + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/double-dollar/double-dollar-textpicker.ets b/ui2abc/arkui-plugins/test/demo/mock/double-dollar/double-dollar-textpicker.ets new file mode 100644 index 0000000000000000000000000000000000000000..8870127ce7707d3ec1223c60a9d8f91d6e08c0e7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/double-dollar/double-dollar-textpicker.ets @@ -0,0 +1,49 @@ +/* + * 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 { Text, Column, Component, TextInput, $$, TextPicker, TextPickerOptions } from "@ohos.arkui.component" +import { State } from "@ohos.arkui.stateManagement" + +@Component +struct MyStateSample { + @State tt: string = "state var"; + @State index: int = 1; + @State select: int = 0; + @State selectArr: int[] = [0, 1, 2]; + fruits: string[] = ['apple1', 'orange2', 'peach3', 'grape4']; + + build() { + Column() { + TextInput({ + text: $$(this.tt) + }) + TextPicker({ + range: this.fruits, + selected: $$(this.select), + value: $$(this.fruits[0]) + } as TextPickerOptions) + TextPicker({ + range: this.fruits, + selected: $$(this.selectArr), + value: $$(this.fruits) + } as TextPickerOptions) + TextPicker({ + range: this.fruits, + selected: $$(this.selectArr), + value: $$(this.fruits[this.index]) + } as TextPickerOptions) + }.margin(10) + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/exports/struct-default-export.ets b/ui2abc/arkui-plugins/test/demo/mock/exports/struct-default-export.ets new file mode 100644 index 0000000000000000000000000000000000000000..c3d086d179e9db5af121e121c1bb971f41a03758 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/exports/struct-default-export.ets @@ -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. + */ + +import { Component, Entry } from "@ohos.arkui.component"; + +@Entry +@Component +export default struct A { + build() {} +} diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets index 1db0074a76a549f58dd45d7ee78a04cbf23e5c25..f1dd349f6877933ba8f5b1c1eda9a4e5d8f3277f 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets @@ -13,14 +13,14 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo function memo_arg_call( +@Memo function memo_arg_call( arg1: number, arg2: (x: number) => number, - @memo arg3: (x: number) => number, + @Memo arg3: (x: number) => number, arg4?: (x: number) => number, - @memo arg5?: (x: number) => number, + @Memo arg5?: (x: number) => number, ) { arg2(arg1) arg3(arg1) @@ -28,11 +28,11 @@ import { memo } from "arkui.stateManagement.runtime"; arg5?.(arg1) } -@memo +@Memo function memo_arg_call_with_lowering( arg1: number, arg4?: (x: number) => number, - @memo arg5?: (x: number) => number, + @Memo arg5?: (x: number) => number, ) { {let gensym___1 = arg4; ((gensym___1 == null) ? undefined : gensym___1(arg1))}; @@ -40,13 +40,33 @@ function memo_arg_call_with_lowering( ((gensym___2 == null) ? undefined : gensym___2(arg1))}; } -@memo +@Memo function args_with_default_values( arg1: int = 10, - @memo arg2: () => int = () => { return 20 }, + @Memo arg2: () => int = () => { return 20 }, arg3: int = arg1, arg4?: int ): void { console.log(arg1, arg2, arg3, arg4) console.log(arg2()) } + +@Memo +function memo_with_non_memo(non_memo_cb: () => void): void { + +} + +function non_memo(cb: () => void): void { + +} + +@Memo +() => { + memo_with_non_memo(() => { + non_memo(() => { + const inner_cb = (msg: string) => { + let obj = msg; + } + }) + }) +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/complex-memo-intrinsic.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/complex-memo-intrinsic.ets index 1ab1a5eba438c895d59b645d3adf02d219c848c7..a8d3fd372651589948318fda1a85a99e2d21286c 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/complex-memo-intrinsic.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/complex-memo-intrinsic.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; @Retention({policy:"SOURCE"}) @interface memo_intrinsic {} @@ -40,7 +40,7 @@ export function cb(callback?: () => void) { @memo_intrinsic export function impl( - @memo + @Memo style: ((attributes: IA) => void) | undefined, arr: SimpleArray, err: string = 'error message' @@ -66,8 +66,8 @@ export function impl( } class Use { - @memo test() { - const style = @memo (attributes: IA) => {}; + @Memo test() { + const style = @Memo (attributes: IA) => {}; const arr = [1, 2, 3, 4]; impl(style, arr); } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets index 9b54856e512b5a835d63ed2a53d91ea11d4db03a..0f9ea4f0c17dddafd174e5a8f08e776d5acefbea 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets @@ -13,34 +13,34 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo +@Memo declare function funcA(): void; class A { - @memo foo() { + @Memo foo() { funcA(); } } -@memo +@Memo function funcB(): void { funcA(); } interface MemoBuilder { - @memo builder: () => void + @Memo builder: () => void } -@memo -function funcWithMemoBuilder(@memo memo_arg: MemoBuilder): void {} +@Memo +function funcWithMemoBuilder(@Memo memo_arg: MemoBuilder): void {} function funcWithArg(arg: () => void): void {} function func(): void {} -@memo +@Memo () => { funcA(); funcWithMemoBuilder({ diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-call.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1c55e27f22530e959bd713683a20012680e7a62 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-call.ets @@ -0,0 +1,48 @@ +/* + * 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 { Memo } from "arkui.incremental.annotation"; + +interface IComponent { + @Memo + builder: () => void; + + itemBuilder: @Memo () => void; + + @Memo + builderFunc(): void; +} + +class PeerNode { + constructor() {} +} + +function createPeerNode(factory: () => PeerNode, @Memo update: () => void): PeerNode { + return factory(); +} + +class A { + public nonMemoMethod(component: IComponent): void { + const updater: (() => PeerNode) = () => { + return createPeerNode((): PeerNode => { + return new PeerNode(); + }, () => { + component.builder(); + component.itemBuilder(); + component.builderFunc(); + }) + } + } +} diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets index 40759ede45a377cb8fa44059707f46eb23b8cd6c..b2db2e22e519fa8bcd6e980bcc3d834a1ab152bf 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets @@ -13,14 +13,14 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo +@Memo function foo() { } -@memo +@Memo function bar() { - const qux = @memo () => { + const qux = @Memo () => { foo(); } @@ -28,9 +28,9 @@ function bar() { } class A { - @memo goo() { + @Memo goo() { let func = () => {}; - let func2 = @memo () => { + let func2 = @Memo () => { foo(); } } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/internal-memo-arg.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/internal-memo-arg.ets index a2970ca5faee655919c785f9da055c1d351891a5..c1b623fd271d71d6e24b8aa2585aeae54bc575f1 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/internal-memo-arg.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/internal-memo-arg.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; import { __memo_context_type, __memo_id_type } from "arkui.incremental.runtime.state"; import { StateContext, IncrementalScope } from "arkui.incremental.runtime.state"; @@ -40,15 +40,15 @@ export declare interface StateManager extends StateContext { export declare function __context(): __memo_context_type export declare function __id(): __memo_id_type -@memo_entry() export function memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: (()=> R)): R { +@memo_entry() export function memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: (()=> R)): R { return entry(); } -@memo_entry() export function memoEntry1(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((arg: T)=> R), arg: T): R { +@memo_entry() export function memoEntry1(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((arg: T)=> R), arg: T): R { return entry(arg); } -@memo_entry() export function memoEntry2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((arg1: T1, arg2: T2)=> R), arg1: T1, arg2: T2): R { +@memo_entry() export function memoEntry2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((arg1: T1, arg2: T2)=> R), arg1: T1, arg2: T2): R { return entry(arg1, arg2); } @@ -62,7 +62,7 @@ export class MemoCallbackContext { this.id = id; } - @memo() public static Make(): MemoCallbackContext { + @Memo() public static Make(): MemoCallbackContext { return new MemoCallbackContext(__context(), __id()); } } @@ -71,9 +71,9 @@ export class MemoCallbackContext { return (__context() as StateManager).valueBy(name); } -@memo_intrinsic() export function contextLocalScope(name: string, value: Value, @memo() content: (()=> void)) { +@memo_intrinsic() export function contextLocalScope(name: string, value: Value, @Memo() content: (()=> void)) { const scope = __context().scope(__id(), 1); - scope.param(0, value, undefined, name, true); + scope.param(0, value); if (scope.unchanged) { scope.cached; } else { @@ -82,7 +82,7 @@ export class MemoCallbackContext { } } -@memo_intrinsic() export function NodeAttach(create: (()=> Node), @memo() update: ((node: Node)=> void), reuseKey?: string): void { +@memo_intrinsic() export function NodeAttach(create: (()=> Node), @Memo() update: ((node: Node)=> void), reuseKey?: string): void { const scope = (__context() as StateManager).scopeEx(__id(), 0, create, undefined, undefined, undefined, reuseKey); if (scope.unchanged) { scope.cached; @@ -105,14 +105,14 @@ export class MemoCallbackContext { return (__context() as StateManager).controlledScope(__id(), invalidate); } -@memo() export function Repeat(count: int, @memo() action: ((index: int)=> void)) { +@Memo() export function Repeat(count: int, @Memo() action: ((index: int)=> void)) { for (let i = 0;((i) < (count));(i++)) { memoEntry1(__context(), i, action, i); } } export class CustomComponent { - @memo() public static _instantiateImpl(): void { + @Memo() public static _instantiateImpl(): void { const context: StateManager = (__context() as StateManager); } } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets index fca54fcc759b39492c91e9636aa77b2399764ff6..808de289193b46d76a57c422a297f3e5df3a9fd5 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets @@ -13,19 +13,19 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo +@Memo function funcNum(): number { return 1; } -@memo +@Memo function funcStr(): string { return "1"; } -@memo +@Memo function funcBool(): boolean { return false; } @@ -34,14 +34,14 @@ interface A { str: string; } -@memo +@Memo function funcA(): A { return { str: "1" }; } type B = (str: string) => void; -@memo +@Memo function funcB(): B { return (str: string) => {}; } @@ -53,12 +53,12 @@ class C { } } -@memo +@Memo function funcC(): C { return new C("1"); } -@memo +@Memo function funcD(): () => void { return () => {}; } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets index fb4e922ace484c2f51b04bd95a69fa51135b73d3..890d9a796104679de2c9f1e32adef629e71adae0 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets @@ -13,28 +13,28 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo type ItemBuilder = (item: Item) => void; +@Memo type ItemBuilder = (item: Item) => void; interface Item { item: T; } interface Attribute { - @memo each(@memo itemGenerator: ItemBuilder): Attribute; + @Memo each(@Memo itemGenerator: ItemBuilder): Attribute; } -@memo +@Memo export declare function A(): Attribute -@memo +@Memo function func(): ItemBuilder { return (item: Item): void => {}; } class B { - @memo build() { + @Memo build() { A().each((ri: Item) => {}) } } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets index 5605e2b68528cfd0c7059d89672b9f3bce69da85..c307cb74ef06252f00b7fa88208c96d3ddeffcce 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets @@ -13,9 +13,9 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo +@Memo function func(): void { return; } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets index 3aa84b3f068470e69dbec6a5546df84b955da9f6..0794d808639dc76a167ae9c992e71163de8c0ade 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets @@ -13,28 +13,28 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; (arg: (()=>void)) => {}(() => {}); -(arg: @memo() (()=>void)) => {}(@memo() () => {}); +(arg: @Memo() (()=>void)) => {}(@Memo() () => {}); -(arg: @memo() (()=>void) = () => {}) => {}(@memo() () => {}); +(arg: @Memo() (()=>void) = () => {}) => {}(@Memo() () => {}); -@memo +@Memo () => { - (@memo() (arg: @memo() (()=>void) = () => {}) => {})(@memo() () => {}); + (@Memo() (arg: @Memo() (()=>void) = () => {}) => {})(@Memo() () => {}); } -@memo +@Memo () => { - let goo = @memo (name: string = "old") => {} + let goo = @Memo (name: string = "old") => {} goo(); } () => { - let foo = (arg: @memo() (()=>void) = () => {}) => {} + let foo = (arg: @Memo() (()=>void) = () => {}) => {} - foo(@memo () => {}); + foo(@Memo () => {}); } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/function-with-receiver.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/function-with-receiver.ets index 4ade068c9d96371c0f1c69234d842196096d851a..2b59fb41b407f588a3a01fcdaac46200255eb399 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/function-with-receiver.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/function-with-receiver.ets @@ -13,20 +13,20 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class B { - @memo internal_call(): B { + @Memo internal_call(): B { this.foo1('morning'); return this.foo2('afternoon') } } -@memo function foo1(this: B, str: string): void { +@Memo function foo1(this: B, str: string): void { console.log('Good', str); } -@memo function foo2(this: B, str: string): this { +@Memo function foo2(this: B, str: string): this { console.log('Good', str); return this; } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets index 1bfdb18b91d4b8d74eda0378c1d582722b904953..bb9e4123a583100cf581dfeff27a4b0924c2d2b5 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets @@ -13,25 +13,25 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class A { - @memo foo(p?: ()=>void): void {} + @Memo foo(p?: ()=>void): void {} - goo(@memo p?: ()=>void): void {} + goo(@Memo p?: ()=>void): void {} - @memo koo(@memo p?: ()=>void): void {} + @Memo koo(@Memo p?: ()=>void): void {} } -@memo +@Memo function bar(f?: ()=>void): void {} -function par(f?: @memo ()=>void): void {} +function par(f?: @Memo ()=>void): void {} -@memo -function kar(@memo f?: ()=>void): void {} +@Memo +function kar(@Memo f?: ()=>void): void {} -@memo +@Memo () => { let a = new A(); a.foo() { console.log(); } diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets index 2f5afae38d6f4aa2b77c1575cdcf6a995b13d48e..e376918be17738b7ec997486a1d588c3744147f4 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets @@ -13,14 +13,14 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; -@memo +@Memo (): void => { return; } -@memo +@Memo (arg?: () => string): void => { return; } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets index 556aba2b53c44be09e8401ec1b53a4fefffb168c..26d428c4600e18d508e8ed49e834c91fb6318985 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets @@ -13,32 +13,32 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class Person { constructor() {} } -@memo -function fullName(this: Person, @memo arg?: () => void): void { +@Memo +function fullName(this: Person, @Memo arg?: () => void): void { return; } class A {} -@memo -type F1 = (this: A, @memo arg?: () => void) => void; +@Memo +type F1 = (this: A, @Memo arg?: () => void) => void; -@memo -type F2 = (a: A, @memo arg?: () => void) => void; +@Memo +type F2 = (a: A, @Memo arg?: () => void) => void; -@memo -function foo(this: A, @memo arg?: () => void): void {} +@Memo +function foo(this: A, @Memo arg?: () => void): void {} -@memo -function goo(a: A, @memo arg?: () => void): void {} +@Memo +function goo(a: A, @Memo arg?: () => void): void {} -@memo +@Memo () => { let x = new Person(); x.fullName(() => {}); diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets index 25903f0435824055e305a26e3cc35c4c0d06c08e..bb41925f754f5bdfe8f87fc14aee886a7c8d39b7 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets @@ -13,23 +13,23 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class Test { - @memo lambda_arg(@memo arg: () => void) { + @Memo lambda_arg(@Memo arg: () => void) { } - @memo lambda_arg_with_arg(@memo arg: (value: string) => string) { + @Memo lambda_arg_with_arg(@Memo arg: (value: string) => string) { } - @memo memo_content(@memo content: () => void) { + @Memo memo_content(@Memo content: () => void) { content() } - @memo compute_test( - @memo arg1: (() => void) | undefined, + @Memo compute_test( + @Memo arg1: (() => void) | undefined, arg2: (() => void) | undefined, content: (() => void) | undefined ): void { @@ -38,7 +38,7 @@ class Test { } class Use { - @memo test() { + @Memo test() { const test = new Test() test.lambda_arg((): void => {}) diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/callable.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/callable.ets index bebbb75019c01d90cec62c17232ca22e16d66002..39c43784f6d0d782d670113fb02a0f6e0b41da42 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/callable.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/callable.ets @@ -13,31 +13,31 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class A { - @memo + @Memo static $_invoke(): void {} } class B { - static $_invoke(@memo p?: () => void): void {} + static $_invoke(@Memo p?: () => void): void {} } class C { - @memo + @Memo static $_instantiate(factory: () => C): C { return factory(); } } class D { - static $_instantiate(factory: () => D, @memo content?: () => void): D { + static $_instantiate(factory: () => D, @Memo content?: () => void): D { return factory(); } } -@memo +@Memo () => { A(); B(() => {}); diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets index 121e1568d790c188fed431cb9a8c618cf1d56f21..6d04bee34a6eec86f3e602abaa40733662b8796c 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets @@ -13,25 +13,25 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; declare abstract class A { - @memo + @Memo x(): void; test_signature( - @memo arg1: () => void, - @memo arg2: (() => void) | undefined, - @memo arg3: ((() => void) | undefined) | ((() => int) | undefined), - @memo x: (y: (z: @memo () => void) => void) => void, - ): @memo () => void; + @Memo arg1: () => void, + @Memo arg2: (() => void) | undefined, + @Memo arg3: ((() => void) | undefined) | ((() => int) | undefined), + @Memo x: (y: (z: @Memo () => void) => void) => void, + ): @Memo () => void; } class AA extends A { - @memo x(): void {} + @Memo x(): void {} } -@memo +@Memo () => { new AA().x(); diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/internal-calls.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/internal-calls.ets index a5559a56ed03395655a09e876026dcab41b48925..f205cd776b589cb80d1af97cad82983f26d97b98 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/internal-calls.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/internal-calls.ets @@ -13,40 +13,40 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; import { __memo_context_type, __memo_id_type } from 'arkui.incremental.runtime.state'; export declare function __context(): __memo_context_type export declare function __id(): __memo_id_type -type MemoType = @memo () => void +type MemoType = @Memo () => void class Test { - @memo void_method(): void { + @Memo void_method(): void { } - @memo internal_call() { + @Memo internal_call() { this.void_method() } - @memo method_with_internals() { + @Memo method_with_internals() { __context() __id() } memo_lambda() { - @memo () => { + @Memo () => { } } - @memo memo_variables() { - @memo const f = (): number => { + @Memo memo_variables() { + @Memo const f = (): number => { return 123 }, g = (x: number): number => { return 123 + x } - const h = @memo (): number => { + const h = @Memo (): number => { return 1 } @@ -55,7 +55,7 @@ class Test { h() } - @memo args_with_default_values( + @Memo args_with_default_values( arg1: int = 10, arg2: () => int = () => { return 20 }, arg3: int = arg1, @@ -65,7 +65,7 @@ class Test { console.log(arg2()) } - @memo optional_args( + @Memo optional_args( arg1?: int, arg2?: () => int ) { @@ -74,7 +74,7 @@ class Test { console.log(arg2?.()) } - @memo type_alias( + @Memo type_alias( arg: MemoType ) { arg() diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/non-void-method.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/non-void-method.ets index 39dd10bb6ad7ff0fc42c81292d6f63c5e813de0d..bde1dabed010b810841b0c1cac09b6b9d65f9a63 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/non-void-method.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/non-void-method.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; import { __memo_context_type, __memo_id_type } from 'arkui.incremental.runtime.state'; @Retention({policy:"SOURCE"}) @interface memo_intrinsic {} @@ -24,14 +24,14 @@ export declare function __context(): __memo_context_type export declare function __id(): __memo_id_type class Test { - @memo void_method(): void { + @Memo void_method(): void { } - @memo string_method_with_return(arg: string): string { + @Memo string_method_with_return(arg: string): string { return arg } - @memo method_with_type_parameter(arg: T): T { + @Memo method_with_type_parameter(arg: T): T { return arg } @@ -44,7 +44,7 @@ class Test { return 0 } - @memo_entry memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo entry: () => R): R { + @memo_entry memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo entry: () => R): R { const getContext = () => { return __context() } @@ -58,7 +58,7 @@ class Test { } } - @memo memo_skip_args(arg1: number, @memo_skip arg2: string, @memo_skip arg3: @memo () => void): string { + @Memo memo_skip_args(arg1: number, @memo_skip arg2: string, @memo_skip arg3: @Memo () => void): string { let a = arg1; arg3(); return arg2; @@ -66,7 +66,7 @@ class Test { } class Use { - @memo test() { + @Memo test() { const test = new Test() test.string_method_with_return("a string") diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/void-method.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/void-method.ets index d2ee07cd7e93b8b41fda05fe6b3fbb99b7c3ba58..a2010b120bcb0578cd07e07f3b34dcc626265cfc 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/methods/void-method.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/methods/void-method.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class A { x: int @@ -21,30 +21,30 @@ class A { } class Test { - @memo void_method(): void { + @Memo void_method(): void { } - @memo a_method_with_implicit_return_type() { + @Memo a_method_with_implicit_return_type() { } - @memo void_method_with_arg(arg: string) { + @Memo void_method_with_arg(arg: string) { } - @memo void_method_with_return(arg: string) { + @Memo void_method_with_return(arg: string) { return } - @memo static static_method_with_type_parameter(arg: T): void { + @Memo static static_method_with_type_parameter(arg: T): void { return } - @memo obj_arg(arg: A) { + @Memo obj_arg(arg: A) { } } class Use { - @memo test() { + @Memo test() { const test = new Test() test.void_method() diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets index a349e0450c4956e6a0a220f7ab61c47a0ebc9866..e6fb1aac71ca2db6224a9a89e17077aac34b1317 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets @@ -13,27 +13,27 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; interface A { - @memo a: () => void + @Memo a: () => void } class AA { - @memo a: (() => void) | undefined + @Memo a: (() => void) | undefined constructor(arg?: A) { this.a = arg?.a; } - @memo + @Memo build() { this.a?.(); } } -@memo +@Memo () => { let a = new AA({ a: () => {} }) ; } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets index 79c72508bb5bed5f84aec0d417feff5052e868af..4e67a45b4bbd9f03e75cd5a0706abeb41f72430c 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets @@ -13,15 +13,15 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; class A { arg: () => void - @memo memo_arg: () => void - @memo memo_optional_arg?: () => void - @memo memo_union_arg: (() => void) | undefined = () => {} + @Memo memo_arg: () => void + @Memo memo_optional_arg?: () => void + @Memo memo_union_arg: (() => void) | undefined = () => {} - arg_memo_type: @memo () => void + arg_memo_type: @Memo () => void constructor() { this.arg = () => {}; @@ -29,7 +29,7 @@ class A { this.arg_memo_type = () => {}; } - @memo + @Memo build() { this.arg(); this.memo_arg(); diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/implements.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/implements.ets index cdf8c6644bbca8d22526707e9cf4d68604003e87..149c170d3a4f18a8d55b26588fbf6d17f7c6af4f 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/implements.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/implements.ets @@ -13,12 +13,12 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; interface A { - @memo prop: (() => void) | undefined + @Memo prop: (() => void) | undefined } class AA implements A { - @memo prop: (() => void) | undefined + @Memo prop: (() => void) | undefined } \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets index 80a9332fd4409f6f40c01232599b0aadb3dee521..9b8125cef25c8fc37d3fd3686ea443bf2f144a71 100644 --- a/ui2abc/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets +++ b/ui2abc/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets @@ -13,18 +13,18 @@ * limitations under the License. */ -import { memo } from "arkui.stateManagement.runtime"; +import { Memo} from "arkui.incremental.annotation"; interface A { arg: () => void - @memo memo_arg: () => void - @memo memo_optional_arg?: () => void - @memo memo_union_arg: (() => void) | undefined + @Memo memo_arg: () => void + @Memo memo_optional_arg?: () => void + @Memo memo_union_arg: (() => void) | undefined - arg_memo_type: @memo () => void + arg_memo_type: @Memo () => void } -@memo() (() => { +@Memo() (() => { let a: A = { arg: (() => {}), memo_arg: (() => {}), diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7466916fbb36a6755ffbad10dd6906e5b4d233f2 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-n-1.ets @@ -0,0 +1,44 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Builder +function func(){ + Text("Fancy") // 'Text("Fancy").height(100).width;' does not meet UI component syntax. + .height(100) + .width +} + +@Entry +@Component +struct UISyntaxErrProperty { + @State enable: boolean = true + + @Builder func(){ + Text("Fancy") // 'Text("Fancy").height(100).width;' does not meet UI component syntax. + .height(100) + .width + } + + build() { + Column() { + Text("Fancy") // 'Text("Fancy").height(100).width;' does not meet UI component syntax. + .height(100) + .width + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..518d917d91b096916a68943e19156cdb71f437c3 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/attribute-no-invoke/attribute-no-invoke-y-1.ets @@ -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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct UISyntaxErrProperty { + @State enable: boolean = true + build() { + Column() { + Text("Fancy") + .height(100) + .width(50) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..0131a7bf7b7ac25ca463e9b237cc8436505f163e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Component +struct Index { + build() { // syntax-error: The 'build' function can have only one root node. + Row() {} + Row() {} + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..b7c3e6c56559c32b1cf7696cd959ef22df982b5f --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { // syntax-error: In an '@Entry' decorated component, the 'build' function can have only one root node, which must be a container component. + Row() {} + Row(){} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..51421ac5216eb1a6b90c5e5ca17378b38a56117a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-n-3.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Component +struct Index { + build() { + Row() {} + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..0131a7bf7b7ac25ca463e9b237cc8436505f163e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Component +struct Index { + build() { // syntax-error: The 'build' function can have only one root node. + Row() {} + Row() {} + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..98bea2a7e1a7b786ae7cebe6c2b1752351343db6 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/build-root-node/build-root-node-y-2.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { + Column() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam-decorator-check_y_1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam-decorator-check_y_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..f12d8527d95c228d404c11f985fd2c39c660fd96 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam-decorator-check_y_1.ets @@ -0,0 +1,50 @@ +/* + * 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 { Entry, Component, BuilderParam, Column, Text, State, Row, Builder } from "@kit.ArkUI" + +@Entry +@Component +struct CustomContainerExport { + header: string = ''; + @BuilderParam closer1: () => void = funA; + + build() { + Column() { + Text(this.header) + .fontSize(50) + this.closer1() + } + } +} + +@Component +struct BuilderParamWithLambda { + @State text: string = 'header'; + build() { + Column() { + CustomContainerExport() { + Row() { + + } + } + } + } +} + +@Builder +function funA() { + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a48a8d13f3856676e9bdffedfb43619812961c67 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_1.ets @@ -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 { Entry, Component, BuilderParam, Column, Text, State, Row, Builder } from "@kit.ArkUI" + +@Entry +@Component +struct CustomContainerExport { + header: string = ''; + @BuilderParam closer1: () => void = funA; + @BuilderParam closer2: () => void = funA; + + build() { + Column() { + Text(this.header) + .fontSize(50) + this.closer1() + } + } +} + +@Component +struct BuilderParamWithLambda { + @State text: string = 'header'; + build() { + Column() { + CustomContainerExport() { + Row() { + + } + } + } + } +} + +@Builder +function funA() { + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_2.ets new file mode 100644 index 0000000000000000000000000000000000000000..0865181d1f9fedf887cee30e2928560e1fb06a93 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/builderparam-decorator-check/builderparam_decorator_check_n_2.ets @@ -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 { Entry, Component, Column, Text, State, Row, Builder } from "@kit.ArkUI" + +@Entry +@Component +struct CustomContainerExport { + header: string = ''; + closer1: () => void = funA; + closer2: () => void = funA; + + build() { + Column() { + Text(this.header) + .fontSize(50) + this.closer1() + } + } +} + +@Component +struct BuilderParamWithLambda { + @State text: string = 'header'; + build() { + Column() { + CustomContainerExport() { + Row() { + + } + } + } + } +} + +@Builder +function funA() { + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..3a19daf7bbf37d7ee9bc8d3dcacdcf8cb7e0c9ce --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-1.ets @@ -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 { Entry, Column, Component, Text } from '@ohos.arkui.component' + +@Entry +@Component +struct Index { + build() { + Column() { + // Property 'aa' is private and can not be initialized through the component constructor. + // Property 'bb' is private and can not be initialized through the component constructor. + // Property 'cc' is private and can not be initialized through the component constructor. + My({aa:"aa",bb:"bb",cc:"cc"}) + } + .height('100%') + .width('100%'); + } +} + +@Component +struct My{ + private aa:string ="" + private bb:string ="" + private cc:string ="" + + build() { + Text(this.aa) + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..06a981ca084fbb94140a17a8eb78662139eae4ba --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-n-2.ets @@ -0,0 +1,69 @@ +/* + * 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 { Entry, Column, Component, Text, Button, ClickEvent } from '@ohos.arkui.component' +import { State, PropRef } from '@ohos.arkui.stateManagement' + +@Component +struct ctComponent { + @PropRef name: string + @PropRef canPlay: boolean + @PropRef count: number + private costOfOneAttempt: number + + build() { + Column() { + if(this.canPlay) { + if (this.count > 0) { + Text(this.name + ' have ' + this.count + ' Nuggets left') + } else { + Text('Sorry, ' + this.name + '. Game over!') + } + + Button(this.name) { + Text('Try again') + }.onClick((e: ClickEvent) => { + this.count -= this.costOfOneAttempt + }) + }else{ + Text(this.name + ', sorry. You do not play this game') + } + } + } +} + +@Entry +@Component +struct PageComponent { + @State countDownStartValue: number = 10 + @State name: string = 'hello world' + build() { + Column() { + Text('Grant ' + this.countDownStartValue + ' nuggets to play') + Button(this.name) { + Text('+1 - Nuggets in New Game') + }.onClick((e: ClickEvent) => { + this.countDownStartValue += 1 + }) + Button(this.name) { + Text('-1 - Nuggets in New Game') + }.onClick((e: ClickEvent) => { + this.countDownStartValue -= 1 + }) + // Property 'costOfOneAttempt' is private and can not be initialized through the component constructor. + ctComponent({ name: 'xiaoming', canPlay: true, count: this.countDownStartValue, costOfOneAttempt: 2}) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..198b379f8cbacee0a662517c920362d4bbb6fdea --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-construct-private-parameter/check-construct-private-parameter-y-1.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, Column, Component, Text } from '@ohos.arkui.component' + +@Entry +@Component +struct Index { + build() { + Column() { + My({aa:"aa",bb:"bb",cc:"cc"}) + } + .height('100%') + .width('100%'); + } +} + +@Component +struct My{ + public aa:string ="" + public bb:string ="" + public cc:string ="" + + build() { + Text(this.aa) + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fa9f8bf7c171691e09da28537b7453741949ed0f --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-1.ets @@ -0,0 +1,41 @@ +/* + * 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 { Entry, Text, Column, Component, CustomDialogController } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Component +struct StateComponent1 { + // The '@State' property 'message' cannot be a 'CustomDialogController' object. + @State message: CustomDialogController = new CustomDialogController({builder:()=>{}}) + build() { + Column(){ + Text('Hello') + } + } +} + +@Entry +@Component +struct StateComponent { + @State message1: string = ''; + // The '@State' property 'message' cannot be a 'CustomDialogController' object. + @State message: CustomDialogController = new CustomDialogController({builder:()=>{}}); + build() { + Column(){ + Text('Hello') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..43a9a3518af70ea2a2e728cae6c0b572f60df398 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-n-2.ets @@ -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 { Entry, Text, Column, Component, CustomDialogController, ComponentV2, BuilderParam } from '@ohos.arkui.component' +import { State, Link, PropRef, Provide, Consume, ObjectLink, StoragePropRef, StorageLink, LocalStorageLink } from '@ohos.arkui.stateManagement' + +@Component +struct StateComponent1 { + // The '@State' property 'message1' cannot be a 'CustomDialogController' object. + // The '@PropRef' property 'message2' cannot be a 'CustomDialogController' object. + // The '@Link' property 'message3' cannot be a 'CustomDialogController' object. + // The '@Provide' property 'message4' cannot be a 'CustomDialogController' object. + // The '@Consume' property 'message5' cannot be a 'CustomDialogController' object. + // The '@ObjectLink' property 'message6' cannot be a 'CustomDialogController' object. + // The '@StoragePropRef' property 'message7' cannot be a 'CustomDialogController' object. + // The '@StorageLink' property 'message8' cannot be a 'CustomDialogController' object. + // The '@StoragePropRef' property 'message9' cannot be a 'CustomDialogController' object. + // The '@LocalStorageLink' property 'message10' cannot be a 'CustomDialogController' object. + @State message1: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @PropRef message2: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @Link message3: CustomDialogController; + @Provide message4: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @Consume message5: CustomDialogController; + @ObjectLink message6: CustomDialogController; + @StoragePropRef('name') message7: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @StorageLink('name') message8: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @StoragePropRef('name') message9: CustomDialogController = new CustomDialogController({builder:()=>{}}); + @LocalStorageLink('name') message10: CustomDialogController = new CustomDialogController({builder:()=>{}}); + build() { + Column(){ + Text('Hello') + } + } +} + +@Entry +@ComponentV2 +struct StateComponent { + // The '@BuilderParam' property 'message' cannot be a 'CustomDialogController' object. + @BuilderParam message: CustomDialogController = new CustomDialogController({builder:()=>{}}); + build() { + Column(){ + Text('Hello') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..75894a8a960bcb86fb6455cefa810c1ad78c8758 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-decorated-property-type/check-decorated-property-type-y-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @State ctrl: number = 1; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..14ee2d0d8ac6413e3abc2a2b6d9c856ca19c5133 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-n-1.ets @@ -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 { Entry, Component, Column, Text, Row, FontWeight } from '@ohos.arkui.component' +import { State, StorageLink, LocalStorageLink, Link, ObjectLink, Observed, StoragePropRef } from '@ohos.arkui.stateManagement' + +@Observed +export class Foo {} + +@Component +struct Index { + @State message: string = 'Hello World'; + + // Property 'storageLink' can not be decorated with both @StorageLink and public. + @StorageLink('name') public storageLink: string = 'name'; + // Property 'storageProp' can not be decorated with both @StoragePropRef and public. + @StoragePropRef('name') public storageProp: string = 'name'; + // Property 'localStorageLink' can not be decorated with both @LocalStorageLink and public. + @LocalStorageLink('name') public localStorageLink: string = 'name'; + // Property 'localStorageProp' can not be decorated with both @StoragePropRef and public. + @StoragePropRef('name') public localStorageProp: string = 'name'; + + // Property 'link' can not be decorated with both @Link and private. + @Link private link: string; + // Property 'objLink' can not be decorated with both @ObjectLink and private. + @ObjectLink private objLink: Foo; + + // The member attributes of a struct can not be protected. + protected regular: string = 'regular'; + // The member attributes of a struct can not be protected. + @State protected state: string = 'state' + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} + +@Entry +@Component +struct A { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..03cb4ed25935d0e0eee86abcbef7108fb465e4b6 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/check-property-modifiers/check-property-modifiers-y-1.ets @@ -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 { Entry, Component, Column, Text, Row, FontWeight } from '@ohos.arkui.component' +import { State, StorageLink, LocalStorageLink, Link, ObjectLink, Observed, StoragePropRef } from '@ohos.arkui.stateManagement' + +@Observed +export class Foo {} + +@Component +export struct Index { + @State message: string = 'Hello World'; + + @StorageLink('name') storageLink: string = 'name'; + @StoragePropRef('name') storageProp: string = 'name'; + @LocalStorageLink('name') localStorageLink: string = 'name'; + @StoragePropRef('name') localStorageProp: string = 'name'; + + @Link link: string; + @ObjectLink objLink: Foo; + + regular: string = 'regular'; + @State state: string = 'state' + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} + +@Entry +@Component +struct A { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..2e0a20fb72039e834fdb153697dc2bdd128926ca --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-n-1.ets @@ -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 { Entry, ComponentV2, Local, Row, Component, Link } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct Parent { + @Local value: number = 1; + build() { + Row() { + ChildV1({ param: this.value }) + } + } +} + +@Component +struct ChildV1 { + @Link param: number; + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f9d7db595d923bfbba96493afb118853e1710ea --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-init/component-componentV2-init-y-1.ets @@ -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 { Entry, ComponentV2, Local, Row, Component, State } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct Parent { + @Local value: number = 1; + build() { + Row() { + ChildV1({ param: this.value }) + } + } +} + +@Component +struct ChildV1 { + @State param: number; + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..526f2bd46fadc9845987d70db756c00cfd5408d9 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-n-1.ets @@ -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 { ObservedV2, LocalStorage, Entry, Component, State, StorageLink, LocalStorageLink, StoragePropRef } from "@kit.ArkUI" + +@ObservedV2 +class Tmp { + showValue: number = 0; +} + +const __get_local_storage__ = () => new LocalStorage(); + +@Entry({ storage: "__get_local_storage__" }) +@Component +struct MyComponent { + @State state_val: Tmp = new Tmp(); + @StorageLink('storageLink') storageLink_val: Tmp = new Tmp(); + @LocalStorageLink('localStorageLink') localStorageLink_val: Tmp = new Tmp(); + @StoragePropRef('storagePropRef') storagePropRef_val: Tmp = new Tmp(); + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7d16eea3b8bd8b3d16d922d9a41478867b36c7b2 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/component-componentV2-mix-use/component-componentV2-mix-use-y-1.ets @@ -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 { Observed, LocalStorage, Entry, Component, State, StorageLink, LocalStorageLink, StoragePropRef } from "@kit.ArkUI" + +@Observed +class Tmp { + showValue: number = 0; +} + +const __get_local_storage__ = () => new LocalStorage(); + +@Entry({ storage: "__get_local_storage__" }) +@Component +struct MyComponent { + @State state_val: Tmp = new Tmp(); + @StorageLink('storageLink') storageLink_val: Tmp = new Tmp(); + @LocalStorageLink('localStorageLink') localStorageLink_val: Tmp = new Tmp(); + @StoragePropRef('storagePropRef') storagePropRef_val: Tmp = new Tmp(); + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..88cd70b9667cd0854f542d334095194df09a57c5 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, ComponentV2 } from '@ohos.arkui.component' +import { State, Watch, Observed } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +@ComponentV2 +struct ComponentV2Test {// syntax-error: The struct 'ComponentV2Test' can not be decorated with '@ComponentV2' and '@Component', '@Reusable', '@CustomDialog' at the same time. + build(){} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..1fdee6566fde2bbd84ef637b86bbc59bd2f58087 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-2.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, ComponentV2, Reusable } from '@ohos.arkui.component' +import { State, Watch, Observed} from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +@Reusable +struct A {// syntax-error: The struct 'A' can not be decorated with '@ComponentV2' and '@Component', '@Reusable', '@CustomDialog' at the same time. + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..ec9fa91e9821ede39a0462b19dba5a06b213988b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-n-3.ets @@ -0,0 +1,26 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, ComponentV2, CustomDialog, CustomDialogController } from '@ohos.arkui.component' +import { State, Watch, Observed} from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +@CustomDialog +struct A {// syntax-error: The struct 'A' can not be decorated with '@ComponentV2' and '@Component', '@Reusable', '@CustomDialog' at the same time. + controller: CustomDialogController = new CustomDialogController({builder:()=>{}}); + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..d1f61d2d592efffe814175e42a2226dc830903ad --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-mix-check/componentV2-mix-check-y-1.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row, ComponentV2 } from '@ohos.arkui.component' +import { State, Watch, Observed} from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct A { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7b0a389e8c461a5fa6eba44fade94dd4a4c70b1c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, ComponentV2, Local, Param } from "@kit.ArkUI" + +interface IMonitor {} + +@Entry +@ComponentV2 +struct MyComponent { + @Local @Param value: string = 'Hello'; + onChange(mon: IMonitor) { + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0b59ad6a1e930af89953a93076c58039239b24c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-2.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Param } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Param value: string; + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..87c288f1ec8ceafe2882a280cacdfb510b94cbfb --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-3.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Local, Require } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Require @Local num: number = 1; + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..078ac6df1814e4f793e7165d27b6fa81d8f746ea --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-4.ets @@ -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 { Entry, ComponentV2, Row } from "@kit.ArkUI" + +@ComponentV2 +struct Child { + num: number = 1; + // @Local num: number = 1; + build() { + } +} + +@Entry +@ComponentV2 +struct MyComponent { + num: number = 1; + build() { + Row() { + Child({ num: this.num }) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ba84786085de06a87da9cee2a9d0f9da12c1da0 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-n-5.ets @@ -0,0 +1,37 @@ +/* + * 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 { Entry, ComponentV2, Local, Param, Event, Component } from "@kit.ArkUI" + +@ComponentV2 +struct Child { + count: number = 0; + + @Param + @Event + @Local + updateCount() { + this.count ++; + } + build() { + } +} + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..5dce4f7205fdeb42bcaf8e6efad8ac5f5b615b78 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, ComponentV2, Local } from "@kit.ArkUI" + +interface IMonitor {} + +@Entry +@ComponentV2 +struct MyComponent { + @Loca value: string = 'Hello'; + onChange(mon: IMonitor) { + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..7e99a0a4356df472aa5f5cb1482c7f1ab16bca81 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-2.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Param, Require } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Param @Require value: string = 'Hello'; + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1d024051919ee1e2f8a4892d84b5ad468802539 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-3.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Param, Require } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Require @Param num: number = 1; + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..f52fde485b78d540fadc242316097bd10d0cdd5a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-4.ets @@ -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 { Entry, ComponentV2, Row } from "@kit.ArkUI" + +@ComponentV2 +struct Child { + num: number = 1; + build() { + } +} + +@Entry +@ComponentV2 +struct MyComponent { + num: number = 1; + build() { + Row() { + Child() + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..19450a7b0bead00f975eccedbc085f9ca54479b2 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/componentV2-state-usage/componentV2-state-usage-y-5.ets @@ -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 { Entry, ComponentV2, Local, Component } from "@kit.ArkUI" + +@ComponentV2 +struct Child { + @Local num: number = 1; + build() { + } +} + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..2487ab65d46387a30aaef59bdb00df776f38d248 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-1.ets @@ -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. + */ + +import { Entry, ObservedV2, Component, Computed } from "@kit.ArkUI" + +@ObservedV2 +class Test { + @Computed + onChange() {} + + @Computed num: number = 1; +} + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..87e871f1e87f75f884f207b5cd74a5943c65a074 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-2.ets @@ -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 { Entry, Observed, Component, Computed } from "@kit.ArkUI" + +@Observed +class Test1 { + @Computed + get getValue(): string { + return '' + } +} + +class Test2 { + @Computed + get getValue(): string { + return '' + } +} + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..6d63ce0a74d34999528cadbf93ac35a8cb33a265 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-3.ets @@ -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 { Entry, Component, Computed } from "@kit.ArkUI" + +@Entry +@Component +struct MyComponent { + @Computed + get getValue(): string { + return ''; + } + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..a2fbd44fb105325e38e259c082a535a28e35a0ad --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-4.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, ComponentV2, Computed, Require, Param, Local, Column, Bindable } from "@kit.ArkUI" + +@ComponentV2 +struct Child { + @Require + @Param + childStr: Bindable; + build() {} +} + +@Entry +@ComponentV2 +struct MyComponent { + @Local str: string = ''; + @Computed + get strFun() { + return this.str; + } + build() { + Column() { + Child({ childStr: $$(this.strFun) }) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..fa4007b35b5c4219faaf1f6785fe6a72388cca7c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-n-5.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, ComponentV2, Computed, Local } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Local str: string = ''; + @Computed + get strFun() { + return this.str; + } + + set strFun(value: string) { + this.str = value; + } + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..ad7168f85d947554d7ed83b9bdeb9ece4f13b1ad --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/computed-decorator/computed-decorator-y-1.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, ComponentV2, Computed, Local } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Local str: string = ''; + @Computed + get strFun() { + return this.str; + } + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..25a2d13bc3d587fa868f1fe969547f1d7795f355 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-1.ets @@ -0,0 +1,36 @@ +/* + * 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 { Entry, Component, Row } from '@ohos.arkui.component' +import { Link } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Foo { + build() { + Row() { + // The 'regular' property '1' cannot be assigned to the '@Link' property 'bar'. + Bar({ bar: 1 }) + } + } +} + +@Component +struct Bar { + @Link bar: number + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..873565f7867dead9f0e650691fbb651ef8b6416b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-2.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, Component, Row } from '@ohos.arkui.component' +import { Observed, ObjectLink } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Foo { + + build() { + Row() { + // syntax-warn: The 'regular' property 'new ClassA()' cannot be assigned to the '@ObjectLink' property 'bar'. (154,8) + Bar({ bar: new ClassA() }) + } + } +} + +@Component +struct Bar { + @ObjectLink bar: ClassA + + build() { + } +} +@Observed +class ClassA {} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..1304bc3599c270a4186058ab2b85e175339b0917 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-3.ets @@ -0,0 +1,52 @@ +/* + * 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 { Entry, Component, Column, Text, ClickEvent } from '@ohos.arkui.component' +import { State, Link, Observed } from '@ohos.arkui.stateManagement' + +@Observed +class ClassA { + public c: number = 0; + + constructor(c: number) { + this.c = c; + } +} + +@Component +struct LinkChild { + @Link testNum: number; + + build() { + Text(`LinkChild testNum ${this.testNum}`) + } +} + +@Entry +@Component +struct Parent { + @State testNum: ClassA[] = [new ClassA(1)]; + + build() { + Column() { + Text(`Parent testNum ${this.testNum[0].c}`) + .onClick((e: ClickEvent) => { + this.testNum[0].c += 1; + }) + // The 'regular' property 'this.testNum[0].c' cannot be assigned to the '@Link' property 'testNum'. + LinkChild({ testNum: this.testNum[0].c }) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..1198a1e84a4ecd8f7242997c56fb313da994b2f2 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-n-4.ets @@ -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 { Entry, Component, Column, Text, Builder } from '@ohos.arkui.component' +import { State, Link } from '@ohos.arkui.stateManagement' + +class ss { + paramA1: string + + constructor(s:string) { + this.paramA1 = s + } +} + +@Entry +@Component +struct Parent { + @State label: string = 'Hello'; + + @Builder ABuilder($$: ss) { + // The 'regular' property 'paramA1' cannot be assigned to the '@Link' property 'message'. + Child({ message: $$.paramA1}) + } + + build() { + Column() { + this.ABuilder(new ss(this.label)) + + } + } +} + +@Component +struct Child { + @Link message: string + + build() { + Column() { + Text(this.message) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..3a3ca61910edd5e74f0ed56630f8685b39b89ffa --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter-literal/construct-parameter-literal-y-1.ets @@ -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 { Entry, Component, Row } from '@ohos.arkui.component' +import { State, ObjectLink, Observed } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Foo { + @State clz: ClassA = new ClassA() + build() { + Row() { + Bar({ bar: this.clz }) + } + } +} + +@Component +struct Bar { + @ObjectLink bar: ClassA + + build() { + } +} +@Observed +class ClassA {} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..d20d741ada337595b1f0c5a039782bfea9884aa7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-1.ets @@ -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 { Entry, Component, ComponentV2, Row } from '@ohos.arkui.component' +import { Link, Observed, ObjectLink } from '@ohos.arkui.stateManagement' + +@Observed +class ClassA {} + +let regularVariable1: number = 10; // variable +let regularVariable2: ClassA = new ClassA(); // variable + +@Entry +@Component +struct Parent { + regular1: number = 10; // regular + regular2: ClassA = new ClassA(); // regular + + build() { + Row() { + // The 'regular' property 'regular2' cannot be assigned to the '@ObjectLink' property 'objectLink2'. + // The 'regular' property 'regularVariable1' cannot be assigned to the '@Link' property 'link1'. + // The 'regular' property 'regular1' cannot be assigned to the '@Link' property 'link2'. + Child1({ + objectLink1: regularVariable2, + objectLink2: this.regular2, + link1: regularVariable1, + link2: this.regular1 + }) + } + } +} + +@Component +struct Child1 { + @ObjectLink objectLink1: ClassA; + @ObjectLink objectLink2: ClassA; + @Link link1: number; + @Link link2: number; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..ccb0be2a6b5445977ce696bcbdbd1f39f256a44b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-2.ets @@ -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 { Entry, Component, Text, Row, Builder, Column } from '@ohos.arkui.component' +import { Link } from '@ohos.arkui.stateManagement' + +@Component +struct MyComponent { + @Link content: () => void; + + build() { + } +} + +@Builder function myBuilder() { + Text('Builder Content') +} + +@Entry +@Component +struct Main { + build() { + Column() { + Row() { + // '@Builder' function 'myBuilder' can only initialize '@BuilderParam' attribute. + MyComponent({ content: myBuilder }) + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..91ffeca2e547ad3a952e23e12aa0f36b3763af75 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-n-3.ets @@ -0,0 +1,44 @@ +/* + * 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 { Entry, Component, Text, Column, BuilderParam, Builder } from '@ohos.arkui.component' + +@Builder +function builderFunc() { + Text('Builder Content') +} + +function regularFunc() { + Text('Builder Content') +} + +@Component +struct MyComponent { + @BuilderParam content: () => void = builderFunc; + + build() { + } +} + +@Entry +@Component +struct Main { + build() { + Column() { + // '@BuilderParam' attribute 'content' can only initialized by '@Builder' function or '@Builder' method in struct. + MyComponent({ content: regularFunc }) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..41304686fdf7bbc1c1d2bc05bf1777b49d715f8c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-1.ets @@ -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 { Entry, Component, Row, Column } from '@ohos.arkui.component' +import { State, PropRef, Link, Provide, ObjectLink, Observed } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Foo { + @State foo: number = 1 + @State objectLink: ClassA = new ClassA() + + build() { + Row() { + Bar ({ + childState: this.foo, + childProp: this.foo, + childLink: this.foo, + childProvide: this.foo, + childObjectLink: this.objectLink, + childRegular: this.foo + }) + } + } +} + +@Component +struct Bar { + @State childState: number = 1; + @PropRef childProp: number = 1; + @Link childLink: number; + @Provide childProvide: number = 1; + @ObjectLink childObjectLink: ClassA; + childRegular: number = 1; + + build() { + } +} + +@Observed +class ClassA {} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..4ff434f6e0376b63263e3bcb98f0da7d85c942df --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/construct-parameter/construct-parameter-y-2.ets @@ -0,0 +1,43 @@ +/* + * 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 { Entry, Component, Text, Builder, Column, BuilderParam } from '@ohos.arkui.component' + +@Component +struct MyComponent { + @BuilderParam content1: () => void = myBuilder; + @BuilderParam content2: () => void = myBuilder; + + build() { + } +} + +@Builder function myBuilder() { + Text('Builder Content') +} + +@Entry +@Component +struct Main { + @Builder mainBuilder() { + Text('Builder Content') + } + + build() { + Column() { + MyComponent({ content1: myBuilder, content2: this.mainBuilder }) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..4032d1752d620eb235c9813939ff162c9bdb0912 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Consumer } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Consumer + test() {} + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..22ba945f12c4d9221eaf76c14e0b7dfe0796ae14 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-2.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Consumer, Param } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Consumer @Param + value: string = ''; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b4897d1de41576d3e71264fb2a12404295a161b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-3.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Provider } from "@kit.ArkUI" + +class Test { + @Provider + value: string = ''; +} + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..53d7df2929a6dc74c0ac28f4e9f9474815339e8e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-n-4.ets @@ -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 { Entry, ComponentV2, Consumer, Row } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + value: string = ''; + build() { + Row() { + Detail({ value: 'Hello' }) + } + } +} + +@ComponentV2 +struct Detail { + @Consumer + value: string = ''; + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6374b0ced065ec84cff2a2d1e454f9ecff21d985 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/consumer-provider-decorator/consumer-provider-decorator-y-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, ComponentV2, Consumer } from "@kit.ArkUI" + +@Entry +@ComponentV2 +struct MyComponent { + @Consumer + value: string = ''; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..8986f9fb5e0a9c40af704a0bcef764f3dc1ae4b4 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, CustomDialog, CustomDialogController } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@CustomDialog +struct CustomDialogExample {// syntax-error: The @CustomDialog decorated custom component must contain a property of the CustomDialogController type. + build() { + Row() {} + } +} + +@Entry +@Component +struct CustomDialogUser { + build() { + Row() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fd1960d600d7d68534939f04217dc37d9d1203cf --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, CustomDialog, CustomDialogController } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@CustomDialog +struct MyComponentA { + controller: CustomDialogController = new CustomDialogController({builder:()=>{}}); + + build(){ + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..092cebb3f8a57f486c11c92d6751c219eb84fa8d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/custom-dialog-missing-controller/custom-dialog-missing-controller-y-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, CustomDialog, CustomDialogController } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@CustomDialog +struct MyComponentA { + controller?: CustomDialogController; + + build(){ + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..dc3fed59f7b5cab0e7c12e84a0eb5b27bd0c71b2 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-n-1.ets @@ -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. + */ + +import { Entry, Component, LocalStorageLink } from "@kit.ArkUI" + +@Entry +@Component +struct Entry_localstorage_1 { + @LocalStorageLink("storageSimpleProp") simpleVarName: number = 0; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a298be13fa03652526d78c249a38edbf56d235fc --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-localstorage/entry-localstorage-y-1.ets @@ -0,0 +1,26 @@ +/* + * 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 { Entry, Component, LocalStorageLink, LocalStorage } from "@kit.ArkUI" + +const __get_local_storage__ = () => new LocalStorage(); + +@Entry({ storage: "__get_local_storage__" }) +@Component +struct Entry_localstorage_1 { + @LocalStorageLink("storageSimpleProp") simpleVarName: number = 0; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..c8d984078bbcb82afc419f470da5250e9afd1f8e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-n-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from "@kit.ArkUI" + +@Entry +@Component +export struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..8bfdd912fd72bf9d5b371d56c757891c3ef6509c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/entry-struct-no-export/entry-struct-no-export-y-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from "@kit.ArkUI" + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..e0a24a6658326ec23e0c77c90c5b70c0273c5bb6 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-n-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Component } from "@kit.ArkUI" + +@Component +struct MyComponent { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..f489c6142995227551b7dcd037e600d3afdf5519 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/main-pages-entry-check/main-pages-entry-check-y-1.ets @@ -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. + */ + +import { Entry, Component } from "@kit.ArkUI" + +@Entry +@Component +struct MyComponent { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..98626e1ed9e071b58d87f317e85bd3c32e251f5e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { State, ObservedV2, Monitor, Computed, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ObservedV2 +class ObservedV2Object { + // syntax-error: The member property or method can not be decorated by multiple built-in annotations. + value: string = "hello" + @Monitor(["value"]) @State onChange(mon:IMonitor) { + console.log("value onChange") + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..621ad1a660ba33b85e351f6a0cb774e64e1a83f7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-2.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { Monitor, Observed, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Observed +class ObservedObject { + name: string = ''; + age: number = 0; + // syntax-error: The '@Monitor' can decorate only member method within a 'class' decorated with @ObservedV2. + @Monitor(["name", "age"]) + onChange(monitor: IMonitor) { + console.log("value onChange") + } + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..d160fb8b871469913bb064c1ff44911cfaa46576 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-3.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { Monitor, Observed, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +class ObservedObject { + name: string = ''; + age: number = 0; + // syntax-error: The '@Monitor' can decorate only member method within a 'class' decorated with @ObservedV2. + @Monitor(["name", "age"]) + onChange(monitor: IMonitor) { + console.log("value onChange") + } + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } +} +@Entry +@Component +struct Greeting { + build() { + } +} diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b45ea2e314ac5984ebc201dafd45850cbc752a8 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-4.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { Monitor, Local, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Test2 { + value: string = "hello" + // syntax-error: The '@Monitor' annotation can only be used in a 'struct' decorated with '@ComponentV2'. + @Monitor(["value"]) onChange(mon:IMonitor) { + console.log("entry onChange") + } + build (){ + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..fb1ffb856061da7a0c2d577bd836370abc675a7b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-n-5.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { Monitor, ObservedV2, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ObservedV2 +class Test2 { + // syntax-error: @Monitor can only decorate method. + @Monitor(["value"]) value: string = 'hello'; + onChange(mon: IMonitor) { + console.log('entry onChange'); + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..26d6fd9cadd4ecb7962005ff62b968f1714193e9 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/monitor-decorator-check/monitor-decorator-check-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { Monitor, ObservedV2, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ObservedV2 +class Test2 { + value: string = "hello" + @Monitor(["value"]) onChange(mon: IMonitor) { + console.log('entry onChange'); + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a4ec65e179c5238a87232c57d9201102d8b5f27a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-1.ets @@ -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. + */ + +import { Entry, Component, Text, Row, Span } from '@ohos.arkui.component' + +@Entry +@Component +struct Index { + build() { + Row() { + Text(){ + // The component 'Span' can't have any child. + Span('Hello World') { + Text('Hello World') + } + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..bd4952729fc795520dee07fa0509d668d0f7181d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-2.ets @@ -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 { Entry, Component, Text, Column, Scroll } from '@ohos.arkui.component' + +@Entry +@Component +struct navel { + build(){ + Column(){ + // The 'Scroll' component can have only one child component. + Scroll(){ + Text('luna') + Text('asahi') + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c0e68adaee26af843732b76fbd923fff0606724 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-3.ets @@ -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 { Entry, Component, Row, Span } from '@ohos.arkui.component' + +@Entry +@Component +struct navel { + build(){ + Row(){ + // The 'Span' component can only be nested in the 'Text,RichEditor,ContainerSpan' parent component. + Span('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..b4c7381db4b4498785adaa7e9abb256e33b883fa --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-n-4.ets @@ -0,0 +1,37 @@ +/* + * 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 { Entry, Component, Text, Column, ContainerSpan } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Example { + @State value: string = 'Hi !'; + + build() { + Column() { + Text(this.value) { + // The component 'ContainerSpan' can only have the child component 'Span,ImageSpan'. + ContainerSpan() { + // The 'Text' component cannot be a child component of the ContainerSpan component. + Text(this.value) + // The 'Text' component cannot be a child component of the ContainerSpan component. + Text('Hello') + } + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..8e5d45d5db077d5299165a1935e43ae50be7e8cf --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-1.ets @@ -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. + */ + +import { Entry, Component, Text, Button, Row, Span, Circle, List, ListItem } from '@ohos.arkui.component' + +@Entry +@Component +struct Index { + build() { + Row() { + List() { + ListItem() + } + Text('Hello World') { + Span('Hello World') + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..6a5a2ca1196ee8950e5f749258be018c43f2ad1b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-relationship/nested-relationship-y-2.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, Component, Row, List, ListItem, ForEach, Text } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @State arr: string[] = ['a', 'b', 'c'] + + build() { + Row() { + List() { + /** + * The 'ForEach' and 'LazyForEach' are not UI component, + * thus, they wouldn't be counted when validating + */ + ForEach(this.arr, (item: string) => { + ListItem(){ + Text(item) + } + }) + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..facc1c03fc990e5f5605220c6840a411754a2647 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-1.ets @@ -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 { Entry, Component, ComponentV2, Column, ReusableV2 } from '@ohos.arkui.component' + +@Entry +@Component +struct V1 { + build() { + Column() { + // A custom component decorated with @Component cannot contain child components decorated with @ReusableV2. + ReuseV2() + } + } +} + +@ReusableV2 +@ComponentV2 +struct ReuseV2 { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..3ac949b76718d30e7d467c9a4ea30831af05c978 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-2.ets @@ -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 { Entry, Component, ComponentV2, Row, Reusable, ReusableV2 } from '@ohos.arkui.component' + +@ReusableV2 +@ComponentV2 +struct ReuseV2 { + build() {} +} + +@Entry +@Reusable +@Component +struct ReuseV1 { + build() { + Row() { + // A custom component decorated with @Reusable cannot contain child components decorated with @ReusableV2. + ReuseV2() + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..2ff4535454d958455b412ac2e0e41116121f4f56 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-3.ets @@ -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 { Entry, Component, ComponentV2, Row, Reusable, ReusableV2 } from '@ohos.arkui.component' + +@Entry +@ReusableV2 +@ComponentV2 +struct ReuseV2 { + build() { + Row() { + // A custom component decorated with @ReusableV2 cannot contain child components decorated with @Reusable. + ReuseV1() + } + } +} + +@Reusable +@Component +struct ReuseV1 { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..cc9616d29ec65dc9351428f2bcc9fdc6ca40f5cc --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-n-4.ets @@ -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 { Entry, ComponentV2, Column, Repeat, RepeatItem, ReusableV2 } from '@ohos.arkui.component' +import { Local } from '@ohos.arkui.stateManagement' + +@Entry +@ComponentV2 +struct validateReusableV2InRepeat { + @Local arr:string[] = ['1','2','3']; + build() { + Column() { + Repeat(this.arr) + .template('temp', (obj: RepeatItem) => { + // The template attribute of the Repeat component cannot contain any custom component decorated with @ReusableV2. + V2R() + }) + } + } +} + +@ReusableV2 +@ComponentV2 +export struct V2R { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..521b88585d97e01943339e312e38dd05a5fc693a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-1.ets @@ -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 { Entry, Component, Row, Reusable } from '@ohos.arkui.component' + +@Reusable +@Component +struct ReuseV1 { + build() {} +} + +@Entry +@Reusable +@Component +struct V1 { + build() { + Row() { + ReuseV1() + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..5ee45201f6a494ab336b0d9ab8834c12bf6e5b33 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-2.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, ComponentV2, Column, ReusableV2 } from '@ohos.arkui.component' + +@Entry +@ComponentV2 +struct V2 { + build() { + Column() { + ReuseV2() + } + } +} + +@ReusableV2 +@ComponentV2 +struct ReuseV2 { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..2706eeb4a60a975c329bb15392344872f063ae4a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/nested-reuse-component-check/nested-reuse-component-check-y-3.ets @@ -0,0 +1,37 @@ +/* + * 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 { Entry, Component, ComponentV2, Column, Reusable, Repeat, RepeatItem } from '@ohos.arkui.component' +import { Local } from '@ohos.arkui.stateManagement' + +@Entry +@ComponentV2 +struct validateReusableV2InRepeat { + @Local arr:string[] = ['1','2','3']; + build() { + Column() { + Repeat(this.arr) + .template('temp', (obj: RepeatItem) => { + // The template attribute of the Repeat component cannot contain any custom component decorated with @ReusableV2. + V1R() + }) + } + } +} + +@Component +export struct V1R { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..d54b291ee2d8e3cd12c357b4d29ab4ea33258324 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-n-1.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Column, Button, Text } from "@ohos.arkui.component"; + +@Entry +@Component +struct Index { + build() { + Column() { + Button('Hello') {// The Button component with a label parameter can not have any child. + Text('Hello') + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..8158aecf6571d32ce442205b766763430b2c5351 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component, Column, Button, Text } from "@ohos.arkui.component"; + +@Entry +@Component +struct Index { + build() { + Column() { + Button('Hello') + Button(){ + + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..b72b76c74f246528292b5ac3f282167ba41fa3ca --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-child-in-button/no-child-in-button-y-2.ets @@ -0,0 +1,26 @@ +/* + * 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 { Entry, Component, Column, Button, Text } from "@ohos.arkui.component"; + +@Entry +@Component +struct Index { + build() { + Column() { + Button('Hello') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..dfa305603ca1e4605dc55ae523848c73c08093de --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { + Column() { + Text('Hello').id('1') + // syntax-warn: The current component id "1" is duplicate with /home/xiar/openharmony0702/developtools/ace_ets2bundle/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets:11:493. + Text('Hi').id('1') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..148c1f92cd0ebd86bc0a8a76a55962f0e2e6e1d7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-n-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { + Column() { + Text('Hello').id('2') + // syntax-warn: The current component id "2" is duplicate with /home/xiar/openharmony0702/developtools/ace_ets2bundle/arkui-plugins/test/demo/localtest/entry/src/main/ets/pages/new.ets:11:501. + Text('Hi').id('1').id('2') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..5e537321feff063c0218d650be7451132712e61a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-id/no-duplicate-id-y-1.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { + Column() { + Text('Hello').id('1') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..45c1783097529c943ecf8fcc70f446a46ea59bf0 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-n-1.ets @@ -0,0 +1,99 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' + +@interface Preview { + +} + +@Entry + // A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct summerpockets { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct ever17 { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct bsd { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct sakuranouta { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct sprb { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct visualarts { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct rewrite { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct air { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct trigger { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct oshinoko { + build(){ + } +} +// A page can contain at most 10 '@Preview' annotations. +@Preview +@Component +struct saki { + build(){ + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fbfc507d77d60fbb023de55e0fe5b6b17a301c2a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-duplicate-preview/no-duplicate-preview-y-1.ets @@ -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 { Entry, Component } from '@ohos.arkui.component' +import { Preview } from '@ohos.arkui.stateManagement' + +@Entry +@Preview +@Component +struct summerpockets { + build(){ + } +} + +@Preview +@Component +struct ever17 { + build(){ + } +} + +@Preview +@Component +struct bsd { + build(){ + } +} + +@Preview +@Component +struct sakuranouta { + build(){ + } +} + +@Preview +@Component +struct sprb { + build(){ + } +} + +@Preview +@Component +struct visualarts { + build(){ + } +} + +@Preview +@Component +struct rewrite { + build(){ + } +} + +@Preview +@Component +struct air { + build(){ + } +} + +@Preview +@Component +struct trigger { + build(){ + } +} + +@Preview +@Component +struct oshinoko { + build(){ + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a432b44b7e50ddf507e65a9b7387baecf9f4a671 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Observed, ObjectLink, State, PropRef } from '@ohos.arkui.stateManagement' + +@Observed class ClassA { + +} + +@Entry +@Component +struct ViewA { + @ObjectLink varA : ClassA; // The '@Entry' component 'ViewA' cannot have the '@ObjectLink' property 'varA'. + build() { + Row() { + Text('ViewA') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..2bdad906ac9af51ec769807ef8c09ec0a40a2ac6 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-2.ets @@ -0,0 +1,26 @@ +/* + * 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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Observed, ObjectLink, State, PropRef } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @PropRef message: string = 'Hello' // The '@Entry' component 'Index' cannot have the '@PropRef' property 'message'. + build() { + Row() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..55d2a0ee813b2cd69f055baf665d527266f5066d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-n-3.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Link } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Greeting{ + @Link varA: string // The '@Entry' component 'Greeting' cannot have the '@Link' property 'varA'. + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..e0e877725b2e1452ecc083d8a3c9d5f57b21273f --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-prop-link-objectlink-in-entry/no-prop-link-objectlink-in-entry-y-1.ets @@ -0,0 +1,61 @@ +/* + * 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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Link, ObjectLink, Observed } from '@ohos.arkui.stateManagement' +@interface PropRef{} + +// use @PropRef in non-entry component +@Component +struct Greeting1{ + @PropRef varA: string = 'xxx' + build() { + } +} + +// use @Link in non-entry component +@Component +struct Greeting2{ + @Link varB: number + build() { + } +} + +// use @ObjectLink in non-entry component +@Component +struct Greeting3{ + @ObjectLink varC: ClassA + build() { + } +} +@Observed class ClassA { +} + +// use @PropRef/@Link/@ObjectLink in non-entry component +@Component +struct Greeting4{ + @PropRef varA: string = 'xxx' + @Link varB: number + @ObjectLink varC: ClassA + build() { + } +} + +@Entry +@Component +struct Index{ + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..01173bf694679c43839c19f808fee982745e8391 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-n-1.ets @@ -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. + */ + +import { Entry, Component } from '@kit.ArkUI' + +@Entry +@Component +struct width { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a5675cacd1f912453fde30bb14dfbbe99800d42b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/no-same-as-built-in-attribute/no-same-as-built-in-attribute-y-1.ets @@ -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. + */ + +import { Entry, Component } from '@kit.ArkUI' + +@Entry +@Component +struct MyComponent { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..d59b602977efeed396fff8c07fd2233c896a22af --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-n-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component } from "@ohos.arkui.component"; + +@Entry +@Component +struct fontColor {// The struct 'fontColor' cannot have the same name as the built-in attribute 'fontColor'. + build() { + } +} + +@Component +struct width {// The struct 'width' cannot have the same name as the built-in attribute 'width'. + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..cb4888324f5e68cd2564d459eb0a50311744a277 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-heritage-compatible-check/no-same-as-built-in-attribute-y-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from "@ohos.arkui.component"; + +@Entry +@Component +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fa14452a2cf81a9e1d5430de507dec97a7a4d493 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-n-1.ets @@ -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 { Entry, Component, ComponentV2 } from "@ohos.arkui.component"; +import { Observed, ObservedV2 } from '@ohos.arkui.stateManagement' + +@Observed// A class cannot be decorated by both '@Observed' and '@ObservedV2' at the same time. +@ObservedV2 +class ObservedObject { + name: string; + age: number; + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } +} +@Entry +@ComponentV2 +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..0948f3885f8ba4a871866d0d7393a8b11867b015 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observed-observedV2-check/observed-observedV2-check-y-1.ets @@ -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 { Entry, Component, ComponentV2 } from "@ohos.arkui.component"; +import { Observed, ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class ObservedObject { + name: string; + age: number; + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } +} +@Entry +@ComponentV2 +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..433217b4a20577182b13804eaf48657d08c86342 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { ObservedV2 } from '@ohos.arkui.stateManagement' + +@Entry +@Component + // The '@ObservedV2' annotation can only be used in 'class'. +@ObservedV2 +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..5ee82d078579cfa6c6cf4733195a32cc95df9799 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-2.ets @@ -0,0 +1,40 @@ +/* + * 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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +// The '@ObservedV2' annotation can only be used in 'class'. +function B(){ + +} + +@ObservedV2 +// The '@ObservedV2' annotation can only be used in 'class'. +interface IUser { + name: string; + age: number; +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..9362c67b2eeb9752742272b26a2720ffb18d6eed --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-3.ets @@ -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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + // The '@Trace' annotation can only be used in 'class'. + @Trace message: string = 'Hello World'; + + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..3f6d92ea3b80e73d7c5b3074b52c081d3f1b5cde --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-4.ets @@ -0,0 +1,43 @@ +/* + * 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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace } from '@ohos.arkui.stateManagement' + +@Trace +// The '@Trace' annotation can only be used in 'class'. +function B(){ + +} + +@Trace +// The '@Trace' annotation can only be used in 'class'. +interface IUser { + name: string; + age: number; +} + +@Entry +@Component +@Trace + // The '@Trace' annotation can only be used in 'class'. +struct Index { + + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..e084a8343e00e897c11f69ec882a1f5344dd793e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-5.ets @@ -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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace, ObservedV2 } from '@ohos.arkui.stateManagement' + +class Bar { + baz: number = 1; + // The '@Trace' annotation can only decorate member variables within a 'class' decorated with '@ObservedV2'. + @Trace quz(): void {} +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-6.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-6.ets new file mode 100644 index 0000000000000000000000000000000000000000..e7e20f4dcd35ed003e42ccebcbf60f9eccb748db --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-6.ets @@ -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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace, ObservedV2 } from '@ohos.arkui.stateManagement' + +class Bar { + // The '@Trace' annotation can only be used within a 'class' decorated with 'ObservedV2'. + @Trace baz: number = 1; + quz(): void {} +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-7.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-7.ets new file mode 100644 index 0000000000000000000000000000000000000000..f9a1c40fa022cdb2eebf7bef308a27f448b87ff5 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-n-7.ets @@ -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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace, Observed } from '@ohos.arkui.stateManagement' + +@Observed +class Bar { + // The '@Trace' annotation can only be used within a 'class' decorated with 'ObservedV2'. + @Trace baz: number = 1; + quz(): void {} +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..c35f39235c6d4e3bbef0a075faab6fc42aff7f1d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class Bar { + +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..fe7372cd51d715f708e0fc7f9fdc35477a133f6c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/observedV2-trace-usage-validation/observedV2-trace-usage-validation-y-2.ets @@ -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 { Entry, Text, Component, Row } from '@ohos.arkui.component' +import { Trace, ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class Bar { + @Trace baz: number = 1; + quz(): void {} +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..f054415a38109180e5228953d7678481f6717ed6 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-1.ets @@ -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. + */ + +import { Entry, Column, Component } from '@ohos.arkui.component' +import { Local } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct NavigationExample { + // The '@Local' annotation can only be used in a 'struct' decorated with '@ComponentV2'. + @Local m:string = 'm'; + + registerInterception() { + } + + build() { + Column() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..844015b1cd89a99b5ef87e6b83c7ce6d43b176be --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-n-2.ets @@ -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 { Entry, ComponentV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +@Entry +@ComponentV2 +struct Test { + //The '@State' annotation can only be used in a 'struct' decorated with '@Component'. + @State value: string = "hello" + + build () { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fcc26fc3732501f0400f90fffe74518ba88eaf6e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/old-new-decorator-mix-use-check/old-new-decorator-mix-use-check-y-1.ets @@ -0,0 +1,46 @@ +/* + * 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 { Entry, Component, ComponentV2 } from '@ohos.arkui.component' +import { State, Computed, Param } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct TestV1 { + @State value: string = "hello" + dd: string = ''; + + get firstName (): string { + return this.value; + } + + build () { + } +} + +@ComponentV2 +struct TestV2 { + @Param value: string = "hello" + + dd:string = ''; + + @Computed + get firstName (): string { + return this.value; + } + + build () { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..418ee0290de16890ad89a3f881504eddde18dfc1 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-1.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { Once, Param } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +struct Index { + value: string = "hello" + + @Once @Param // @Once can only decorate member property. + bb() {} + + build() { + Column() + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..822e767e12c8d0c790e7edcd1e0d4b1e74985274 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { Once, Local } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +struct testParam { + @Once value1: string = "hello" // When a variable decorated with '@Once', it must also be decorated with '@Param'. + build() { + Column() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..49cfa68e4ce9dbcbbf6bc403dff45a07c23d8c9f --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-n-3.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { Once, Param } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +class Index { // '@Once' annotation can only be used with 'struct'. + @Once @Param + value: string = "hello" + + bb() {} + + build() { + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a21cd5306d1afad72026547a23664c505c4f88be --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { Once, Param } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +struct Index { + @Param @Once val: string = "myValue"; + build() { + Column() { + Text(this.val); + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..e7072f935b0830ddac08bedcfa62c07a9223337e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/once-decorator-check/once-decorator-check-y-2.ets @@ -0,0 +1,92 @@ +/* + * 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 { Event, Param, Local, Once, Consumer, Provider, ObservedV2, Trace, Require } from "@ohos.arkui.stateManagement" +import { Entry, ComponentV2, Column, Text } from "@ohos.arkui.component" + +export const STATE_VARIABLES_V2: string = 'StateVariablesV2' + +@Entry +@ComponentV2 +struct StateVariablesV2Main { + son0: Son0 = new Son0(); + son1: Son1 = new Son1(); + son2: Son2 = new Son2(); + + local_var_0: string = ""; + local_var_1: string = ""; + local_var_2: string = ""; + + @Provider("alias_0") provider_var_0: string = ""; + @Provider("alias_1") provider_var_1: string = ""; + @Provider("alias_2") provider_var_2: string = ""; + + @Event event0: ()=>void = ()=>{}; + @Event event1: ()=>void = ()=>{}; + @Event event2: ()=>void = ()=>{}; + + + build() { + Column() { + StateVariablesV2Child({ + param_var_0: this.local_var_0, + param_var_1: this.local_var_1, + param_var_2: this.local_var_2, + + once_para_var_0: this.local_var_0, + once_para_var_1: this.local_var_1, + once_para_var_2: this.local_var_2, + + }) + } + } +} + +@ComponentV2 +struct StateVariablesV2Child { + @Param param_var_0: string =""; + @Param param_var_1: string =""; + @Param param_var_2: string =""; + + @Require @Once @Param once_para_var_0: string; + @Require @Once @Param once_para_var_1: string; + @Require @Once @Param once_para_var_2: string; + + @Consumer("alias_0") consumer_var_0: string = ""; + @Consumer("alias_1") consumer_var_1: string = ""; + @Consumer("alias_2") consumer_var_2: string = ""; + + build() { + Column() { + Text(`Text`) + } + } +} + + +@ObservedV2 +class Son0 { + @Trace age: number = 100; +} + +@ObservedV2 +class Son1 { + @Trace age: number = 100; +} + +@ObservedV2 +class Son2 { + @Trace age: number = 100; +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..ecb65d6d1fed9ae52a9d936fafc8169416942dc7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-1.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Builder } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Builder // A function can only be decorated by the 'Builder'. +@State // A function can only be decorated by the 'Builder'. +function ff() { + +} + +@Entry +@Component +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..ba49fb4713c5b1fb6fec11072bf257ccca8902ad --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-n-2.ets @@ -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 { AnimatableExtend, Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@AnimatableExtend // A function can only be decorated by the 'Builder'. +function animatableWidth(width:number): number{ + return width; +} + +@Entry +@Component +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..134bb10f6b6c7decb5e71826323e60c8ec967baf --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Builder } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Builder +function ff() { +} + +@Entry +@Component +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..183a8687ca84772cf2016f3443b193778790a435 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/one-decorator-on-function-method/one-decorator-on-function-method-y-2.ets @@ -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. + */ + +import { AnimatableExtend, Entry, Text, TextAttribute, Column, Component, Button, ClickEvent, Row, ComponentV2, Reusable, ReusableV2, CustomDialog, Builder, BuilderParam } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@AnimatableExtend +function animatableWidth(this: TextAttribute, width:number): this{ + this.width(width); + return this; +} + +@Entry +@Component +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..23f3fb5c6d988c13693717dc8c6656fe766738bd --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-1.ets @@ -0,0 +1,39 @@ +/* + * 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 { Entry, Text, ComponentV2, Row, Column , Component } from '@ohos.arkui.component' +import { ObservedV2, PropRef, ObjectLink, Local } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class A {} + +@Entry +@ComponentV2 +struct Parent { + @Local value: A = new A() + + build() { + Column() { + Child({ value: this.value }) + } + } +} + +@Component +struct Child { + @ObjectLink value: A + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..df04c9929dfd4cdd4a5f2ab2bd1e379a38b533b8 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-2.ets @@ -0,0 +1,65 @@ +/* + * 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 { Entry, Component, Color } from '@ohos.arkui.component' +import { ObjectLink, ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class ClassA { + public a: string = "default"; +} + +@Component +struct ExampleComponent { + // Boolean + @ObjectLink flag1: boolean | undefined; + + // String + @ObjectLink str1: string | undefined; + + // Number + @ObjectLink num1: number | undefined; + + // BigInt + @ObjectLink bigNum1: bigint | undefined; + + // StringLiteral + @ObjectLink greeting1: "hello" | undefined; + + // BigIntLiteral + @ObjectLink id1: undefined; + + @ObjectLink myClass: ClassA | null; + + @ObjectLink undefined1: undefined | null; + + @ObjectLink null1: null | undefined; + + @ObjectLink any1: Any | undefined; + + @ObjectLink color1: Color + + build() { + + } +} + +@Entry +@Component +struct MyComponent { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..18e150342a7635aa67f36af50faa5567270ea42c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-3.ets @@ -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 { Entry, Component } from '@ohos.arkui.component' +import { PropRef } from '@ohos.arkui.stateManagement' + +@Component +struct SomeComponent { + @PropRef + myState: bigint // The '@PropRef' decorated attribute 'myState' must be of the string, number, boolean, enum or object type. + + build() { + } +} + +@Entry +@Component +struct MyComponent { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..7742507a926fcf426f2c33d857d52b1a129e6c9c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-4.ets @@ -0,0 +1,43 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' +import { PropRef } from '@ohos.arkui.stateManagement' + +@Component +struct ExampleComponent { + + //@PropRef prop1: Any; // error + + @PropRef prop2: bigint; // error + + @PropRef prop3: Any | undefined; // error + + @PropRef prop4: bigint | undefined; // error + + @PropRef prop5: null | undefined | Any; // error + + build() { + + } +} + +@Entry +@Component +struct MyComponent { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..59c89405cb06262f3c23682dc16baf1cdb034e26 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-n-5.ets @@ -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 { Entry, Component, Row, Column, BuilderParam } from '@ohos.arkui.component' +import { PropRef } from '@ohos.arkui.stateManagement' + +@Component +struct Child { + @BuilderParam componentBuilder: string = 'Hello'; //'@BuilderParam' property can only be initialized by '@Builder' function or 'Builder' method in struct. + build() { + Row() {} + } +} + +@Entry +@Component +struct Parent { + build() { + Column() { + Child() + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..4b0a2b7636a3e25f58a3f2d76e6c9087884425c3 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/property-type/property-type-y-1.ets @@ -0,0 +1,49 @@ +/* + * 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 { Entry, Component, Row, Column, BuilderParam, Builder } from '@ohos.arkui.component' +import { ObjectLink, PropRef, Observed } from '@ohos.arkui.stateManagement' + +@Component +struct Child { + @PropRef myState:string = 'xxx'; + @ObjectLink varA : ClassB; + @Builder funB(){ + } + @Builder static funC(){ + } + @BuilderParam componentBuilder: () => void = funA; + @BuilderParam componentBuilder1: () => void = this.funB; + @BuilderParam componentBuilder2: () => void = Child.funC; + build() { + Row() {} + } +} + +@Entry +@Component +struct Parent { + build() { + + } +} + +@Observed class ClassB { + +} + +@Builder function funA(){ + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6b9b220ccad37f3b5f0df6288cdb551af9f67a22 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Builder, BuilderParam } from '@ohos.arkui.component' +import { PropRef, Require } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + build() { + Row() { + } + } +} +@Component +struct Child { + @Require @BuilderParam private initBuildText: () => void = buildFunction; // Property 'initBuildText' can not be decorated with both Require and private. + @Require @PropRef private message: string = 'Hello'; // Property 'message' can not be decorated with both Require and private. + @Require @PropRef private initMessage: string; // Property 'initMessage' can not be decorated with both Require and private. + build() { + } +} +@Builder +function buildFunction() { +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7503cdb460306c120edaf65583f5b6a5c7f37324 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/require-decorator-regular/require-decorator-regular-y-1.ets @@ -0,0 +1,36 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2 } from '@ohos.arkui.component' +import { PropRef, Require } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Component +struct Bar { + @Require @PropRef myState: string = 'Hello' + @Require normalVariable: string = 'Hello' + + foo() { + } + + build() { + } +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..03661e95e88d0b63d950f7661f42d7e62b0f3775 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-n-1.ets @@ -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 { Entry, Reusable, Component, ComponentV2, Row } from '@ohos.arkui.component' + +@Entry +@ComponentV2 +struct V2 { + build() { + Row(){ + // When a custom component is decorated with @ComponentV2 and contains a child component decorated with @Reusable, the child component will not create. + ReuseV1() + } + } +} + +@Reusable +@Component +struct ReuseV1 { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6027e19ff83b427dcb3d4206e1ef20e8fa7a0b51 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusable-component-in-V2-check/reusable-component-in-V2-check-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, ReusableV2, ComponentV2, Column } from '@ohos.arkui.component' + +@Entry +@ComponentV2 +struct V2 { + build() { + Column() { + ReuseV2() + } + } +} + +@ReusableV2 +@ComponentV2 +struct ReuseV2 { + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..11152bdf96116298dd18fdc70e5dce217d47a3d0 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Reusable +@ReusableV2 +@ComponentV2 struct V2{ // The '@Reusable' and '@ReusableV2' annotations cannot be applied simultaneously. + build() {} +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..2a311c36c6d96811b15152a17fdd9ae346563199 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-n-2.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ReusableV2 +@Component struct V1 { // @ReusableV2 is only applicable to custom components decorated by @ComponentV2. + build() {} +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..27fbf6911781266c0a3ebd671679de1e1c02302a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reusableV2-decorator-check/reusableV2-decorator-check-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ReusableV2 +@ComponentV2 struct V2{ + build() {} +} +@Entry +@Component +struct Greeting { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6fb32e14d47c1963bff4e4735c7d974a7bf5c3dd --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-1.ets @@ -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 { Entry, Component, Row, Column, ComponentV2 } from '@ohos.arkui.component' + +@Component struct V1{ + build() { + } +} +@ComponentV2 struct V2{ + build() { + } +} + +@Entry +@ComponentV2 struct Parent { + build() { + Row(){ + V2().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + V1().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..fd92168b2064065787b7d4691a1e482400ca0853 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-2.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component, Row, Column, ComponentV2, Reusable } from '@ohos.arkui.component' + +@Entry +@Reusable @Component struct ReuseV1{ + build() { + } +} +@Component struct Parent { + build() { + Row(){ + ReuseV1().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..64d9f48d88a22dac73a9bc2e3727f3b88f96e46d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-n-3.ets @@ -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 { Entry, Component, Row, Column, ComponentV2, ReusableV2 } from '@ohos.arkui.component' + +@ReusableV2 +@ComponentV2 +struct reusableV2{ + build() { + } +} +@Entry +@ComponentV2 +struct Parent { + build() { + Row() { + reusableV2() + .reuseId("V2") // The reuseId attribute is not applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7649b55be04a14e496a22209e18266fa3bbbd894 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Component, Row, Column, ComponentV2, ReusableV2 } from '@ohos.arkui.component' + +@Entry +@ReusableV2 @ComponentV2 struct ReuseV1{ + build() { + } +} +@ComponentV2 struct Parent { + build() { + Row(){ + ReuseV1().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..27bde2b6fe31279ef6ef18bded60181d48ed9771 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/reuse-attribute-check/reuse-attribute-check-y-2.ets @@ -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 { Entry, Component, Row, Column, ComponentV2, Reusable } from '@ohos.arkui.component' + +@Reusable +@Component +struct reusableV2{ + build() { + } +} +@Entry +@ComponentV2 +struct Parent { + build() { + Row() { + reusableV2() + .reuseId("V2") // The reuseId attribute is not applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6fb32e14d47c1963bff4e4735c7d974a7bf5c3dd --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-1.ets @@ -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 { Entry, Component, Row, Column, ComponentV2 } from '@ohos.arkui.component' + +@Component struct V1{ + build() { + } +} +@ComponentV2 struct V2{ + build() { + } +} + +@Entry +@ComponentV2 struct Parent { + build() { + Row(){ + V2().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + V1().reuse({reuseId: ()=>"V2"}) // The reuse attribute is only applicable to custom components decorated with both @ComponentV2 and @ReusableV2. + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..857488522e2b2515120b3f332435a7100aa18f54 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-2.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +@Entry +@Component +struct A { + @State + myState: string = 'Hello World' + + build() { + } + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..39d878c4f64a18b595a9e658225b22fea171f088 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-3.ets @@ -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. + */ + +@Entry +@Component +struct A { + @Require @State value: string + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..27dd59d6d9404722f44ab8e3dbbfe032eada1596 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-4.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +@Entry +@Component +struct A { + // variables 'myState' decorated by '@Prop' should not be initialized + @Prop + myState: string = 'Hello World' + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-5.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-5.ets new file mode 100644 index 0000000000000000000000000000000000000000..7a3eff56405f22ecca075e9686e7a4d0f3c9cfde --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/specific-component-children/struct-variable-initialization-5.ets @@ -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. + */ + +@Entry +@Component +struct A { + @Prop + myState: string + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..28a810119868483dcd20ef90cb0942f5c627c63e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-n-1.ets @@ -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 { Entry, Text, Column, Component, ComponentV2 } from '@ohos.arkui.component' +import { Param, Require } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct TestStaticVariableAssignment { + build() { + Column() { + // Static property 'a1' can not be initialized through the component constructor. + StaticChildOne({ a1: 'a11', a2: 'a22' }) + // Static property 'b4' can not be initialized through the component constructor. + // Static property 'b5' can not be initialized through the component constructor. + StaticChildTwo({ + b4: 'b44', + b5: 'b55' + }) + // Static property 'c1' can not be initialized through the component constructor. + StaticChildThree({ c1: 'c11', c2: 'c22' }) + // Static property 'd4' can not be initialized through the component constructor. + // Static property 'd5' can not be initialized through the component constructor. + StaticChildFour({ + d1: 'd11', + d4: 'd44', + d5: 'd55' + }) + } + .height('100%') + .width('100%') + } +} + +@Component +struct StaticChildOne { + static a1: string = 'a1'; + a2: string = 'a2'; + build() { + Column() { + Text('a1: ' + StaticChildOne.a1) + Text('a2: ' + this.a2) + } + } +} + +@ComponentV2 +struct StaticChildTwo { + @Param static b4: string = 'b4'; + @Require @Param static b5: string = 'b5'; + build() { + Column() { + Text('b4: ' + StaticChildTwo.b4) + Text('b5: ' + StaticChildTwo.b5) + } + } +} + +@Component +export struct StaticChildThree { + static c1: string = 'c1'; + c2: string = 'c2'; + build() { + Column() { + Text('c1: ' + StaticChildThree.c1) + Text('c2: ' + this.c2) + } + } +} + +@ComponentV2 +export struct StaticChildFour { + static d1: string = 'd1'; + @Param static d4: string = 'd4'; + @Require @Param static d5: string = 'd5'; + build() { + Column() { + Text('d1: ' + StaticChildFour.d1) + Text('d4: ' + StaticChildFour.d4) + Text('d5: ' + StaticChildFour.d5) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a7bfe67dce39a2d40e915891cc24bbfbd1e7fef4 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/static-param-require/static-param-require-y-1.ets @@ -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 { Entry, Text, Column, Component, ComponentV2 } from '@ohos.arkui.component' +import { Param, Require } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct TestStaticVariableAssignment { + build() { + Column() { + StaticChildOne({ a2: 'a22' }) + StaticChildTwo({ + b4: 'b44', + b5: 'b55' + }) + } + .height('100%') + .width('100%') + } +} + +@Component +struct StaticChildOne { + static a1: string = 'a1'; + a2: string = 'a2'; + build() { + Column() { + Text('a1: ' + StaticChildOne.a1) + Text('a2: ' + this.a2) + } + } +} + +@ComponentV2 +struct StaticChildTwo { + @Param b4: string = 'b4'; + @Require @Param b5: string = 'b5'; + build() { + Column() { + Text('b4: ' + this.b4) + Text('b5: ' + this.b5) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..ebd34d0cb03d3bd9306c453e3c794508f8180d06 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-1.ets @@ -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 { Entry, Component } from '@ohos.arkui.component' + +class Base { + +} + +@Entry +@Component +struct MyComponent extends Base { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..8de81d735bb0653aade281bb233f1a404f21d5df --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-n-2.ets @@ -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 { Entry, Component } from '@ohos.arkui.component' + +interface Base { + +} + +@Entry +@Component +struct MyComponent implements Base { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..b8c13aa62ab42dcf5d006783b937ab7719dc6b76 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-no-extends/struct-no-extends-y-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..98c11bcfa079483bc8211aa9b0b9b385ffa6b525 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct StaticVar { + // The static variable of struct cannot be used together with built-in annotations. + @State static mess: string = 'Hello' + build() { + Column(){ + Text(StaticVar.mess) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..ad690954e6c6f7858df5f879d0e3f28672ff9544 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { Param } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@ComponentV2 +struct StaticVar { + // The static variable of struct cannot be used together with built-in annotations. + @Param static mess: string = 'Hello' + build() { + Column(){ + Text(StaticVar.mess) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..626802958347a4672eadaf24e13199baf7715beb --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-n-3.ets @@ -0,0 +1,37 @@ +/* + * 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 { Entry, Text, Column, Component, ComponentV2, Button } from '@ohos.arkui.component' +import { Monitor, ObservedV2, IMonitor } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@ObservedV2 +class Test2 { + value: string = "hello" + @Monitor(["value"]) static onChange(mon: IMonitor) { + console.log('entry onChange'); + } +} +@Entry +@ComponentV2 +struct Greeting { + value: string = "hello" + @Monitor(["value"]) static onChange(mon: IMonitor) { + console.log('entry onChange'); + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a6eb89ec63393436f3b9f257e1bbae6605c18d48 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-decorator/struct-property-decorator-y-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State, Param } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct MyComponentA { + @State count: number = 0 + static CNT: number = 0 + build(){ + } +} + +@ComponentV2 +struct MyComponentB { + @Param count: number = 0 + static CNT: number = 0 + build(){ + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..62478d4b68dddc2a3163a6290dd73783d64f33c7 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-n-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Component, PropRef, Link } from '@kit.ArkUI' + +@Entry +@Component +struct MyComponent { + @PropRef isShow?: boolean; + @Link isOn?: boolean; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..286559d505f7238cbddf2c03e39b74aff488f84d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-property-optional/struct-property-optional-y-1.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Component, PropRef, Link } from '@kit.ArkUI' + +@Entry +@Component +struct MyComponent { + @PropRef isShow?: boolean = false; + @Link isOn: boolean; + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..09137208f5db0f71dacf3eb64c3d23983372837d --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-1.ets @@ -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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Link, State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Parent { + @State state: string = 'text' + build() { + Column() { + Child({link: this.state}) + } + } +} + +@Component +struct Child { + @Link link: string = 'text' // The 'Link' property cannot be specified a default value. + build() { + Column() { + Text('text') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..582139ce801bb3a636899a2a608bff6cfd22157c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-2.ets @@ -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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State } from '@ohos.arkui.stateManagement' + +@Component +struct TitleComp { + @Link title: string + build() { + Text(this.title) + } +} + + +@Component +struct LinkComponent{ + @State value: string = 'hello world' + @Link linkVariable: string = 'hello link' // The 'Link' property cannot be specified a default value. + @Builder + TitleCompView() { + TitleComp({title: this.value}) + } + build() { + Row() { + this.TitleCompView() + } + } +} + +@Entry +@Component +struct Child { + build() { + Column() { + Text('text') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..396cd299964efaad3f52ee16bb5c4b860c31d5f1 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-3.ets @@ -0,0 +1,43 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State, Observed, ObjectLink } from '@ohos.arkui.stateManagement' + +@Observed +class observe { + +} + +@Entry +@Component +struct Parent { + @State state: observe = new observe() + build() { + Column() { + Child({objectLink: this.state}) + } + } +} + +@Component +struct Child { + @ObjectLink objectLink: observe = new observe() // The 'ObjectLink' property cannot be specified a default value. + build() { + Column() { + Text('text') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-4.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-4.ets new file mode 100644 index 0000000000000000000000000000000000000000..cb531e8a39022a59142a2d2680739ac7f13c4cd8 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-n-4.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State, Observed, ObjectLink } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @State message: string // The 'State' property must be specified a default value. + + build() { + Row() { + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..37e535cde46ef36d683e30db4f7a4857be60ad47 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-1.ets @@ -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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State, Observed, ObjectLink, Consume } from '@ohos.arkui.stateManagement' + +@Observed +class observe { + +} + +@Entry +@Component +struct Index { + @Consume c: number + build() { + Row() {} + } +} + +@Component +struct Child { + @ObjectLink objectLink: observe; + @Link link: string + build() { + Column() { + Text('text') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..704a6a31b3bbb4abf3c21127b85225b524c90ec8 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-2.ets @@ -0,0 +1,25 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State, Observed, ObjectLink, Consume, Require } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct A { + @Require @State value: string + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..306273e450775e459d44b6f5767ea6f9941efc8e --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/struct-variable-initialization/struct-variable-initialization-y-3.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Row, Column, Text, Builder } from '@ohos.arkui.component' +import { Link, State, Observed, ObjectLink, Consume, Require } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct A { + @State + myState: string = 'Hello World' + + build() { + } + +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..abb6d78372a9a7ff42310dbc6b53bd477e8ad36c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-1.ets @@ -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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Track } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @Track message: string = 'Hello Word!' // The '@Track' annotation can decorate only member variables of a class. + build() { + Row() { + Column() { + Text('hello') + .fontSize(50) + } + .width('100%') + } + .height('100%') + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..4d498695ac2c7c72aa4aa7f97b805a0599d16cea --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-2.ets @@ -0,0 +1,50 @@ +/* + * 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 { Entry, Component, Row, Column, Text } from '@ohos.arkui.component' +import { Track } from '@ohos.arkui.stateManagement' + +@Track +// The '@Track' annotation can decorate only member variables of a class. +let A: number = 0; + +@Track +// The '@Track' annotation can decorate only member variables of a class. +function B(){ + +} + +@Track +// The '@Track' annotation can decorate only member variables of a class. +interface IUser { + name: string; + age: number; +} + +@Entry +@Component +struct Index { + @Track + // The '@Track' annotation can decorate only member variables of a class. + funA(){ + + } + + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..06a497368d47e76a6cfac9a021e13e4872ac1c3a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-n-3.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Row, Column, Text, ComponentV2 } from '@ohos.arkui.component' +import { Track, ObservedV2 } from '@ohos.arkui.stateManagement' + +@ObservedV2 +class ObservedV2Object { + @Track message: number = 0 // '@Track' cannot be used with classes decorated by '@ObservedV2'. Use the '@Trace' annotation instead. +} +@Entry +@ComponentV2 +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..acb9f106cc05f650e44831073abbcd54cd63fc90 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/track-decorator-check/track-decorator-check-y-1.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Component, Row, Column, Text, ComponentV2 } from '@ohos.arkui.component' +import { Track } from '@ohos.arkui.stateManagement' + +class A { + @Track name: string = ''; +} + +@Entry +@ComponentV2 +struct Index { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a19e4707a50ce7b77ec2204f10812f8a628dac34 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-n-1.ets @@ -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 { Entry, Row, Component, Text, FontWeight, Builder } from '@ohos.arkui.component' + +@Builder +function customBuilder() { + Text('123') + .fontColor('#ffff') + .borderColor("#fff") + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .padding('12vp') + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .borderWidth("10vp") + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .borderRadius("10vp") + .borderWidth("10px") + .borderRadius("10px") + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .outlineWidth("10vp") + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .outlineRadius("10vp") + .outlineWidth("10px") + .outlineRadius("10px") + .fontWeight(FontWeight.Bold) + // It is recommended that you use layered parameters for easier color mode switching and theme color changing. + .foregroundColor("#ffffffff") +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('123') + .fontColor('#ffff') + .borderColor("#fff") + .padding('12px') + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .borderWidth("10vp").borderRadius("10vp") + .borderWidth("10px").borderRadius("10px") + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + // It is recommended that you use layered parameters for polymorphism development and resolution adaptation. + .outlineWidth("10vp").outlineRadius("10vp") + .outlineWidth("10px").outlineRadius("10px") + .fontWeight(FontWeight.Bold) + // It is recommended that you use layered parameters for easier color mode switching and theme color changing. + .foregroundColor("#ffffffff") + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..22fb14b0427ddcbb6300d3464440f5d3f67a267a --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/ui-consistent-check/ui-consistent-check-y-1.ets @@ -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 { Entry, Row, Component, Text, FontWeight, Builder, $r } from '@ohos.arkui.component' + +@Builder +function customBuilder() { + Text('123') + .fontColor('#ffff') + .borderColor("#fff") + .padding($r('sys.float.corner_radius_level6')) + .borderWidth($r('sys.float.corner_radius_level5')) + .borderRadius($r('sys.float.corner_radius_level5')) + .borderWidth("10px") + .borderRadius("10px") + .outlineWidth($r('sys.float.corner_radius_level5')) + .outlineRadius($r('sys.float.corner_radius_level5')) + .outlineWidth("10px") + .outlineRadius("10px") + .fontWeight(FontWeight.Bold) + .foregroundColor($r('sys.color.navigation_drag_bar_item_default')) +} + +@Entry +@Component +struct Index { + build() { + Row() { + Text('123') + .fontColor('#ffff') + .borderColor("#fff") + .padding('12px') + .borderWidth($r('sys.float.corner_radius_level5')).borderRadius($r('sys.float.corner_radius_level5')) + .borderWidth("10px").borderRadius("10px") + .outlineWidth($r('sys.float.corner_radius_level5')).outlineRadius($r('sys.float.corner_radius_level5')) + .outlineWidth("10px").outlineRadius("10px") + .fontWeight(FontWeight.Bold) + .foregroundColor($r('sys.color.navigation_drag_bar_item_default')) + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..6746a0edd47f6c1ff91d117cc955760b2c362bf9 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' + +@Entry +@Component +struct MyComponent { + build(a: number) { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..cee01eab819572ee07bf8be8da552ffdf635b714 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-2.ets @@ -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. + */ + +import { Entry, Component } from '@ohos.arkui.component' + +@Entry +@Component +struct MyComponent { +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..aa831b0f5cabc883d54b20917cc0ac4d37ef747c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-n-3.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' + +@Entry +@Component +struct MyComponent { + build() {} + build() {} +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..b8c13aa62ab42dcf5d006783b937ab7719dc6b76 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-build-in-struct/validate-build-in-struct-y-1.ets @@ -0,0 +1,23 @@ +/* + * 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 { Entry, Component } from '@ohos.arkui.component' + +@Entry +@Component +struct MyComponent { + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..58221b991ea36ae2ad4c5fa87c874705d11fa138 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-1.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Reusable // The '@Reusable' annotation can only be used with 'struct'. +class A {} + +@Entry +@Component +struct B { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..70936ac1e698b4b44f13f301513472e0736eb345 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-2.ets @@ -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 { Entry, Component, Row, Column, Text, Reusable } from '@ohos.arkui.component' + +// The '@Reusable' annotation can only be used with 'struct'. +@Reusable +let A: number = 0; + +// The '@Reusable' annotation can only be used with 'struct'. +@Reusable +function B(){ + +} + +// The '@Reusable' annotation can only be used with 'struct'. +@Reusable +class C { + @Reusable + A: number = 0; + + @Reusable + funA(){ + + } +} + +// The '@Reusable' annotation can only be used with 'struct'. +@Reusable +interface IUser { + name: string; + age: number; +} + +@Entry +@Component +struct Index { + // The '@Reusable' annotation can only be used with 'struct'. + @Reusable A: number = 0; + + // The '@Reusable' annotation can only be used with 'struct'. + @Reusable + funA(){ + + } + + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-3.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-3.ets new file mode 100644 index 0000000000000000000000000000000000000000..a1dccb6916a3e0f0c8788399ad278b3a5ae2dd8b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-n-3.ets @@ -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 { Entry, Component, Row, Column, Text, Reusable } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' + +// '@State' can only decorate member property. +@State +let A: number = 0; + +// '@State' can only decorate member property. +@State +function B(){ + +} + +// '@State' can only decorate member property. +@State +class C { + @State + A: number = 0; + + @State + funA(){ + + } +} + +// '@State' can only decorate member property. +@State +interface IUser { + name: string; + age: number; +} + +@Entry +@Component + // '@State' can only decorate member property. +@State +struct Index { + @State A: number = 0; + + // '@State' can only decorate member property. + @State + funA(){ + + } + + build() { + Row() { + Text('Hello World') + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a4b16522e9b29860ffaf08563a27505b228de031 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-1.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Reusable +@Component +struct B { + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..098d3eafb401fb9028e364647e36895b5f11eb70 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/validate-decorator-target/validate-decorator-target-y-2.ets @@ -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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Banner { + @State + myState: string = 'Hello' + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..cbf460fcc1b0f96440a05adc1bab1a5461a0246b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-1.ets @@ -0,0 +1,47 @@ +/* + * 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 { Entry, Row, Component, Builder, BuilderParam } from '@ohos.arkui.component' +import { State, Provide, Require, PropRef } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + build() { + Row() { + // '@Require' decorated 'initBuildText' must be initialized through the component constructor. + // '@Require' decorated 'messageProp' must be initialized through the component constructor. + // '@Require' decorated 'initMessage' must be initialized through the component constructor. + // '@Require' decorated 'messageState' must be initialized through the component constructor. + // '@Require' decorated 'messageProvide' must be initialized through the component constructor. + Child() + } + } +} +@Component +struct Child { + @Require @BuilderParam initBuildText: () => void = buildFunction; + @Require @PropRef messageProp: string = 'Hello'; + @Require @PropRef initMessage: string; + @Require @State messageState: string = 'Hello'; + @Require @Provide messageProvide: string = 'Hello'; + @PropRef childProp: string; + @BuilderParam childBuildParam: () => void = buildFunction; + build() { + } +} +@Builder +function buildFunction() { +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..196a7d97b745a66cc7f146b65714306ee316acae --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-n-2.ets @@ -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 { Entry, Column, Component } from '@ohos.arkui.component' +import { StoragePropRef,State } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Parent { + @State message: string = 'Hello'; + + build() { + Column() { + // The '@StoragePropRef' property 'message' in the custom component 'Child' cannot be initialized here (forbidden to specify). + Child({message: this.message}); + } + } +} + +@Component +struct Child { + @StoragePropRef('111') message: string = 'Hello'; + build() { + + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..2268d73048a43132a3ab22b454480d37f4e90b03 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/variable-initialization-via-component-cons/variable-initialization-via-component-cons-y-1.ets @@ -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 { Entry, Row, Component, Builder, BuilderParam } from '@ohos.arkui.component' +import { State, Provide, Require, PropRef, StoragePropRef, StorageLink, Consume, LocalStorageLink } from '@ohos.arkui.stateManagement' + +@Entry +@Component +struct Index { + @State message: string = 'Hello'; + build() { + Row() { + Child({ + initBuildText: buildFunction, + messageProp: this.message, + initMessage: this.message, + messageState: this.message, + messageProvide: this.message + }) + } + } +} +@Component +struct Child { + @Require @BuilderParam initBuildText: () => void = buildFunction; + @Require @PropRef messageProp: string = 'Hello'; + @Require @PropRef initMessage: string; + @Require @State messageState: string = 'Hello'; + @Require @Provide messageProvide: string = 'Hello'; + @StoragePropRef('111') messageStoragePropRef: string = 'Hello'; + @StorageLink('111') messageStorageLink: string = 'Hello'; + @Consume('111') messageConsume: string = 'Hello'; + @LocalStorageLink('111') messageLocalStorageLink: string = 'Hello'; + build() { + } +} +@Builder +function buildFunction() { +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..bee0e596c0651729d9e457e24892078720a92ca4 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-1.ets @@ -0,0 +1,28 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State, Watch } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + // '@watch' cannot be used with 'onWatch'. Apply it only to parameters that correspond to existing methods. + @State @Watch('onWatch') message: Array = ['1','2','3','4','5'] + build() { + Row() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..8da947b5edcd344071f557c9c78dacb90371305b --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-n-2.ets @@ -0,0 +1,29 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State, Watch } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Index { + private msg: string = '100' + // '@Watch' cannot be used with 'msg'. Apply it only to 'string' parameters. + @State @Watch(this.msg) defArray: Array = ['c', 'g', 't', 'z']; + build() { + Row() {} + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..e51a31fa010fc5221d8bb20b1f564a21ef39ef90 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-function/watch-decorator-function-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State, Watch } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Banner { + @Watch('foo') + @State + myState: string = 'Hello' + + foo(myState: string) { + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..a9075560401680af0fe7b2e66699ae78a1eea633 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-n-1.ets @@ -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. + */ + +import { Entry, Text, Column, Component, Button, ClickEvent, Row, Scroll, ComponentV2, Reusable, ReusableV2 } from '@ohos.arkui.component' +import { State, Watch } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Banner { + @Watch('foo') // syntax-error: Regular variable 'message' can not be decorated with '@Watch'. + myState: string = 'Hello' + + foo() { + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..7ddebe3425c5da2cc7821bb54d4776a0a765b51c --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/watch-decorator-regular/watch-decorator-regular-y-1.ets @@ -0,0 +1,32 @@ +/* + * 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 { Entry, Text, Column, Component, Button, ClickEvent, Row, ComponentV2, Reusable, CustomDialog } from '@ohos.arkui.component' +import { State, Watch } from '@ohos.arkui.stateManagement' +import hilog from '@ohos.hilog' + +@Entry +@Component +struct Banner { + @Watch("foo") + @State + myState: string = 'Hello' + + foo(myState: string) { + } + + build() { + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..8623bc84734c96a63722a4b6b3b2ee507cd4c828 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-1.ets @@ -0,0 +1,36 @@ +/* + * 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 { Entry, Component, Row, WrappedBuilder, wrapBuilder, Builder, Text } from '@ohos.arkui.component' + +type MyBuilderFuncType = @Builder (value: string, size: number) => void; + +@Entry +@Component +struct A { + @Builder + myBuilder(value: string, size: number) { + Text(value).fontSize(size) + } + + // The wrapBuilder's parameter should be @Builder function. + wrap: WrappedBuilder = wrapBuilder(this.myBuilder) + + build() { + Row() { + + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-2.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-2.ets new file mode 100644 index 0000000000000000000000000000000000000000..875fc1e0e046ad832b52dec19ab454e95445bba1 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-n-2.ets @@ -0,0 +1,47 @@ +/* + * 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 { Entry, Component, Column, WrappedBuilder, wrapBuilder, Builder, Text, Stack, BuilderParam } from '@ohos.arkui.component' + +type MyBuilderFuncType = @Builder (value: string, size: number) => void; + +interface FormItemBuilderInterface { + buildView(): WrappedBuilder; +} + +class DesktopForm implements FormItemBuilderInterface { + public buildView(): WrappedBuilder { + // The wrapBuilder's parameter should be @Builder function. + return wrapBuilder(buildFormItem); + } +} + +function buildFormItem(value: string, size: number) { + Text(value).fontSize(size) +} + +@Entry +@Component +struct AppFormItemView { + @BuilderParam buildInterface?: FormItemBuilderInterface; + + build() { + Column() { + Stack() { + + } + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-y-1.ets b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-y-1.ets new file mode 100644 index 0000000000000000000000000000000000000000..fbafbf31416eb46189a05dd047d00bd828cf1b99 --- /dev/null +++ b/ui2abc/arkui-plugins/test/demo/mock/ui-syntax/wrap-builder-check/wrap-builder-check-y-1.ets @@ -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 { Entry, Component, Row, WrappedBuilder, wrapBuilder, Builder, Text } from '@ohos.arkui.component' + +type MyBuilderFuncType = @Builder (value: string, size: number) => void; + +@Builder +function funcBuilder(value: string, size: number) { + Text(value).fontSize(size) +} + +@Entry +@Component +struct A { + wrap: WrappedBuilder = wrapBuilder(funcBuilder) + + build() { + Row() { + + } + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/ut/common/annotation.test.ts b/ui2abc/arkui-plugins/test/ut/common/annotation.test.ts index 465e64a4eb38af1ce19731dd8e1dee68130605b0..7f1faa63fe5e839c176c2ab95014d0b157b75a1a 100644 --- a/ui2abc/arkui-plugins/test/ut/common/annotation.test.ts +++ b/ui2abc/arkui-plugins/test/ut/common/annotation.test.ts @@ -161,10 +161,12 @@ import { Component as Component, ResourceStr as ResourceStr, Builder as Builder @TestAnno() (() => {}) @TestAnno() class A { @TestAnno() public prop: number = 1; - @TestAnno() public method(@TestAnno() arg1: number): void { + @TestAnno() + public method(@TestAnno() arg1: number): void { @TestAnno() const a: number = arg1; } - @TestAnno() public constructor() {} + @TestAnno() + public constructor() {} } @TestAnno() interface __A { @TestAnno() prop: number; @@ -177,16 +179,19 @@ function testParseAnnotation(this: PluginTestContext): void { const expectedCheckSnapshot: string = ` import { Component as Component, ResourceStr as ResourceStr, Builder as Builder } from "@ohos.arkui.component"; -@TestAnno() function main() {} +@TestAnno() +function main() {} @TestAnno() (() => {}); @Retention({policy:\"SOURCE\"}) @interface TestAnno {} @TestAnno() type TestType = number; @TestAnno() class A { @TestAnno() public prop: number = 1; - @TestAnno() public method(@TestAnno() arg1: number): void { + @TestAnno() + public method(@TestAnno() arg1: number): void { @TestAnno() const a: number = arg1; } - @TestAnno() public constructor() {} + @TestAnno() + public constructor() {} } @TestAnno() interface __A { ${dumpGetterSetter(GetSetDumper.BOTH, 'prop', 'number', [dumpAnnotation('TestAnno')], [dumpAnnotation('TestAnno')], false)} diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts index 52c62b67be6e36359a78101d9dae7e70c073b86a..170ddb19c4c83660346ac7bfeb31a93c8ebb619e 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts @@ -32,7 +32,8 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function memo_arg_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, arg2: ((x: number)=> number), @memo() arg3: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number), arg4?: ((x: number)=> number), @memo() arg5?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number)) { +@Memo() +function memo_arg_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, arg2: ((x: number)=> number), @Memo() arg3: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number), arg4?: ((x: number)=> number), @Memo() arg5?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 5); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2), __memo_parameter_arg3 = __memo_scope.param(2, arg3), __memo_parameter_arg4 = __memo_scope.param(3, arg4), __memo_parameter_arg5 = __memo_scope.param(4, arg5); if (__memo_scope.unchanged) { @@ -50,7 +51,8 @@ function main() {} return; } } -@memo() function memo_arg_call_with_lowering(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, arg4?: ((x: number)=> number), @memo() arg5?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number)) { +@Memo() +function memo_arg_call_with_lowering(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, arg4?: ((x: number)=> number), @Memo() arg5?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number)=> number)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 3); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg4 = __memo_scope.param(1, arg4), __memo_parameter_arg5 = __memo_scope.param(2, arg5); if (__memo_scope.unchanged) { @@ -70,16 +72,17 @@ function main() {} return; } } -@memo() function args_with_default_values(__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: int, @memo() gensym%%_?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int), gensym%%_?: int, arg4?: int): void { - let arg1: int = (((gensym%%_) !== (undefined)) ? gensym%%_ : (10 as int)); - let arg2: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int) = (((gensym%%_) !== (undefined)) ? gensym%%_ : (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() +function args_with_default_values(__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: int, @Memo() gensym%%_?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int), gensym%%_?: int, arg4?: int): void { + let arg1: int = (((gensym%%_) !== (undefined)) ? gensym%%_ : 10); + let arg2: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int) = (((gensym%%_) !== (undefined)) ? gensym%%_ : ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(20); - }) as ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int))); - let arg3: int = (((gensym%%_) !== (undefined)) ? gensym%%_ : (arg1 as int)); + })); + let arg3: int = (((gensym%%_) !== (undefined)) ? gensym%%_ : arg1); const __memo_scope = __memo_context.scope(((__memo_id) + ()), 4); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2), __memo_parameter_arg3 = __memo_scope.param(2, arg3), __memo_parameter_arg4 = __memo_scope.param(3, arg4); if (__memo_scope.unchanged) { @@ -93,6 +96,41 @@ function main() {} return; } } + +@Memo() +function memo_with_non_memo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, non_memo_cb: (()=> void)): void { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_non_memo_cb = __memo_scope.param(0, non_memo_cb); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + { + __memo_scope.recache(); + return; + } +} + +function non_memo(cb: (()=> void)): void {} + +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + memo_with_non_memo(__memo_context, ((__memo_id) + ()), (() => { + non_memo((() => { + const inner_cb = ((msg: string) => { + let obj = msg; + }); + })); + })); + { + __memo_scope.recache(); + return; + } +}); `; function testMemoTransformer(this: PluginTestContext): void { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/complex-memo-intrinsic.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/complex-memo-intrinsic.test.ts index 451dc27342a95a1e552fab61ace60184832487de..9d7da504bf034387383e45fd11740dbd2ba8cdda 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/complex-memo-intrinsic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/complex-memo-intrinsic.test.ts @@ -44,7 +44,8 @@ import { memo as memo } from "arkui.stateManagement.runtime"; function main() {} -@memo_intrinsic() export function factory(__memo_context: __memo_context_type, __memo_id: __memo_id_type, compute: (()=> Value)): Value +@memo_intrinsic() +export function factory(__memo_context: __memo_context_type, __memo_id: __memo_id_type, compute: (()=> Value)): Value export function cb(callback?: (()=> void)) { if (callback) { @@ -52,8 +53,9 @@ export function cb(callback?: (()=> void)) { } } -@memo_intrinsic() export function impl(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() style: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type, attributes: IA)=> void) | undefined), arr: SimpleArray, gensym%%_1?: string): void { - let err: string = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : ("error message" as string)); +@memo_intrinsic() +export function impl(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() style: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type, attributes: IA)=> void) | undefined), arr: SimpleArray, gensym%%_1?: string): void { + let err: string = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : "error message"); const s = factory(__memo_context, ((__memo_id) + (90010973)), (() => { return new A(); })); @@ -107,13 +109,14 @@ class A implements IA { export type SimpleArray = (Array | ReadonlyArray | Readonly>); class Use { - @memo() public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (228150357)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - const style = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, attributes: IA) => { + const style = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, attributes: IA) => { const __memo_scope = __memo_context.scope(((__memo_id) + (237001330)), 1); const __memo_parameter_attributes = __memo_scope.param(0, attributes); if (__memo_scope.unchanged) { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts index 96a5e8b07cf2bb61d3db8635182ee5e731e9012e..00607740a69f4c739f79c1208b5c1f60f5006d46 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts @@ -35,8 +35,10 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function funcA(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void -@memo() function funcB(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { +@Memo() +function funcA(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void +@Memo() +function funcB(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -48,7 +50,8 @@ function main() {} return; } } -@memo() function funcWithMemoBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() memo_arg: MemoBuilder): void { +@Memo() +function funcWithMemoBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() memo_arg: MemoBuilder): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_memo_arg = __memo_scope.param(0, memo_arg); if (__memo_scope.unchanged) { @@ -62,7 +65,7 @@ function main() {} } function funcWithArg(arg: (()=> void)): void {} function func(): void {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -92,7 +95,8 @@ function func(): void {} } }); class A { - @memo() public foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -107,7 +111,7 @@ class A { public constructor() {} } interface MemoBuilder { - ${dumpGetterSetter(GetSetDumper.BOTH, 'builder', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('memo')], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builder', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('Memo')], [], false)} } `; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-call.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1d8ee01d476ede512f370cad59cec5c12e90a41 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-call.test.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 path from 'path'; +import { PluginTester } from '../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; +import { parseDumpSrc } from '../../../utils/parse-string'; +import { beforeMemoNoRecheck, memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; + +const FUNCTION_DIR_PATH: string = 'memo/functions'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'inner-call.ets')]; + +const pluginTester = new PluginTester('test memo inner call', buildConfig); + +const expectedScript: string = ` +function main() {} +function createPeerNode(factory: (()=> PeerNode), @Memo() update: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): PeerNode { + return factory(); +} +interface IComponent { + @Memo() + get builder(): ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) + @Memo() + set builder(builder: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) + get itemBuilder(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) + set itemBuilder(itemBuilder: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) + @Memo() + builderFunc(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void +} + +class PeerNode { + public constructor() {} +} + +class A { + public nonMemoMethod(component: IComponent): void { + const updater: (()=> PeerNode) = (() => { + return createPeerNode(((): PeerNode => { + return new PeerNode(); + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + component.builder(__memo_context, ((__memo_id) + ())); + component.itemBuilder(__memo_context, ((__memo_id) + ())); + component.builderFunc(__memo_context, ((__memo_id) + ())); + { + __memo_scope.recache(); + return; + } + })); + }); + } + public constructor() {} +} +`; + +function testMemoTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'transform inner calls in functions', + [beforeMemoNoRecheck, memoNoRecheck, recheck], + { + 'checked:memo-no-recheck': [testMemoTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts index cad12bd80f4dde1bd0d35515a15f41ef320c163a..1634135d87fb807ce22e8b20dde7d6dea49c6073 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts @@ -34,7 +34,8 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { +@Memo() +function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -45,13 +46,14 @@ function main() {} return; } } -@memo() function bar(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { +@Memo() +function bar(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - const qux = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const qux = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -70,14 +72,15 @@ function main() {} } } class A { - @memo() public goo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public goo(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } let func = (() => {}); - let func2 = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + let func2 = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/internal-memo-arg.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/internal-memo-arg.test.ts index 240197a657da7a4e2e53619a7df8a7c33b4d6820..1834629a5a740700523383137e881b5edd1b60ca 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/internal-memo-arg.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/internal-memo-arg.test.ts @@ -50,25 +50,30 @@ export function __context(): __memo_context_type export function __id(): __memo_id_type -@memo_entry() export function memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> R)): R { +@memo_entry() +export function memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> R)): R { return entry(__memo_context, ((__memo_id) + (75311131))); } -@memo_entry() export function memoEntry1(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T)=> R), arg: T): R { +@memo_entry() +export function memoEntry1(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T)=> R), arg: T): R { return entry(__memo_context, ((__memo_id) + (168506859)), arg); } -@memo_entry() export function memoEntry2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: T1, arg2: T2)=> R), arg1: T1, arg2: T2): R { +@memo_entry() +export function memoEntry2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: T1, arg2: T2)=> R), arg1: T1, arg2: T2): R { return entry(__memo_context, ((__memo_id) + (76962895)), arg1, arg2); } -@memo_intrinsic() export function contextLocalValue(__memo_context: __memo_context_type, __memo_id: __memo_id_type, name: string): Value { +@memo_intrinsic() +export function contextLocalValue(__memo_context: __memo_context_type, __memo_id: __memo_id_type, name: string): Value { return (__memo_context as StateManager).valueBy(name); } -@memo_intrinsic() export function contextLocalScope(__memo_context: __memo_context_type, __memo_id: __memo_id_type, name: string, value: Value, @memo() content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { +@memo_intrinsic() +export function contextLocalScope(__memo_context: __memo_context_type, __memo_id: __memo_id_type, name: string, value: Value, @Memo() content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { const scope = __memo_context.scope(__memo_id, 1); - scope.param(0, value, undefined, name, true); + scope.param(0, value); if (scope.unchanged) { scope.cached; } else { @@ -77,7 +82,8 @@ export function __id(): __memo_id_type } } -@memo_intrinsic() export function NodeAttach(__memo_context: __memo_context_type, __memo_id: __memo_id_type, create: (()=> Node), @memo() update: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, node: Node)=> void), reuseKey?: string): void { +@memo_intrinsic() +export function NodeAttach(__memo_context: __memo_context_type, __memo_id: __memo_id_type, create: (()=> Node), @Memo() update: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, node: Node)=> void), reuseKey?: string): void { const scope = (__memo_context as StateManager).scopeEx(__memo_id, 0, create, undefined, undefined, undefined, reuseKey); if (scope.unchanged) { scope.cached; @@ -105,11 +111,13 @@ export function __id(): __memo_id_type } } -@memo_intrinsic() export function rememberControlledScope(__memo_context: __memo_context_type, __memo_id: __memo_id_type, invalidate: (()=> void)): ControlledScope { +@memo_intrinsic() +export function rememberControlledScope(__memo_context: __memo_context_type, __memo_id: __memo_id_type, invalidate: (()=> void)): ControlledScope { return (__memo_context as StateManager).controlledScope(__memo_id, invalidate); } -@memo() export function Repeat(__memo_context: __memo_context_type, __memo_id: __memo_id_type, count: int, @memo() action: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, index: int)=> void)) { +@Memo() +export function Repeat(__memo_context: __memo_context_type, __memo_id: __memo_id_type, count: int, @Memo() action: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, index: int)=> void)) { const __memo_scope = __memo_context.scope(((__memo_id) + (200707415)), 2); const __memo_parameter_count = __memo_scope.param(0, count), __memo_parameter_action = __memo_scope.param(1, action); if (__memo_scope.unchanged) { @@ -153,7 +161,8 @@ export class MemoCallbackContext { this.id = id; } - @memo() public static Make(__memo_context: __memo_context_type, __memo_id: __memo_id_type): MemoCallbackContext { + @Memo() + public static Make(__memo_context: __memo_context_type, __memo_id: __memo_id_type): MemoCallbackContext { const __memo_scope = __memo_context.scope(((__memo_id) + (41727473)), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; @@ -164,7 +173,8 @@ export class MemoCallbackContext { } export class CustomComponent { - @memo() public static _instantiateImpl(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public static _instantiateImpl(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + (214802466)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts index 2817d830dd8b6fe0c2f85977ac1a216a1feec975..fd0a4c7d7da40dd14e47e4471bf7cdce61b65a50 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts @@ -35,28 +35,32 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function funcNum(__memo_context: __memo_context_type, __memo_id: __memo_id_type): number { +@Memo() +function funcNum(__memo_context: __memo_context_type, __memo_id: __memo_id_type): number { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(1); } -@memo() function funcStr(__memo_context: __memo_context_type, __memo_id: __memo_id_type): string { +@Memo() +function funcStr(__memo_context: __memo_context_type, __memo_id: __memo_id_type): string { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(\"1\"); } -@memo() function funcBool(__memo_context: __memo_context_type, __memo_id: __memo_id_type): boolean { +@Memo() +function funcBool(__memo_context: __memo_context_type, __memo_id: __memo_id_type): boolean { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(false); } -@memo() function funcA(__memo_context: __memo_context_type, __memo_id: __memo_id_type): A { +@Memo() +function funcA(__memo_context: __memo_context_type, __memo_id: __memo_id_type): A { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; @@ -65,21 +69,24 @@ function main() {} str: \"1\", }); } -@memo() function funcB(__memo_context: __memo_context_type, __memo_id: __memo_id_type): B { +@Memo() +function funcB(__memo_context: __memo_context_type, __memo_id: __memo_id_type): B { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(((str: string) => {})); } -@memo() function funcC(__memo_context: __memo_context_type, __memo_id: __memo_id_type): C { +@Memo() +function funcC(__memo_context: __memo_context_type, __memo_id: __memo_id_type): C { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; } return __memo_scope.recache(new C(\"1\")); } -@memo() function funcD(__memo_context: __memo_context_type, __memo_id: __memo_id_type): (()=> void) { +@Memo() +function funcD(__memo_context: __memo_context_type, __memo_id: __memo_id_type): (()=> void) { const __memo_scope = __memo_context.scope<(()=> void)>(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts index b596c76ecbd4eea0762629fe552df6026a3a2a1d..0ddc3ce1b40392d8d9413464ce5d1a8ca2933a41 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts @@ -35,8 +35,10 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() export function A(__memo_context: __memo_context_type, __memo_id: __memo_id_type): Attribute -@memo() function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): ItemBuilder { +@Memo() +export function A(__memo_context: __memo_context_type, __memo_id: __memo_id_type): Attribute +@Memo() +function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): ItemBuilder { const __memo_scope = __memo_context.scope>(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; @@ -54,15 +56,17 @@ function main() {} } })); } -@memo() type ItemBuilder = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: Item)=> void); +@Memo() type ItemBuilder = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: Item)=> void); interface Item { ${dumpGetterSetter(GetSetDumper.BOTH, 'item', 'T', [], [], false)} } interface Attribute { - @memo() each(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() itemGenerator: ItemBuilder): Attribute + @Memo() + each(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() itemGenerator: ItemBuilder): Attribute } class B { - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts index 29a63d607ba4ea30db53e2668dadad4ad611bc60..d9b4b938f83b205a398c162194387e66e883f98e 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts @@ -34,7 +34,8 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { +@Memo() +function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts index 360a724c8b35141bbbd841e735bf1d94d0f1b022..de9d00d789dd24d5f21cf205e833436396913f11 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts @@ -34,7 +34,7 @@ import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} ((arg: (()=> void)) => {})((() => {})); -((arg: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => {})(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +((arg: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => {})(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -46,8 +46,8 @@ function main() {} } })); -((gensym%%_1?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { - let arg: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +((gensym%%_1?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { + let arg: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (201676739)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -57,8 +57,8 @@ function main() {} __memo_scope.recache(); return; } - }) as @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))); -})(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + })); +})(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (209782503)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -70,14 +70,14 @@ function main() {} } })); -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { - let arg: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { + let arg: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -87,7 +87,7 @@ function main() {} __memo_scope.recache(); return; } - }) as @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))); + })); const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -98,7 +98,7 @@ function main() {} __memo_scope.recache(); return; } - })(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + })(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -115,14 +115,14 @@ function main() {} } }); -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - let goo = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: string) => { - let name: string = (((gensym%%_) !== (undefined)) ? gensym%%_ : (\"old\" as string)); + let goo = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_?: string) => { + let name: string = (((gensym%%_) !== (undefined)) ? gensym%%_ : \"old\"); const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_name = __memo_scope.param(0, name); if (__memo_scope.unchanged) { @@ -142,8 +142,8 @@ function main() {} }); (() => { - let foo = ((gensym%%_?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { - let arg: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + let foo = ((gensym%%_?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) => { + let arg: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -153,9 +153,9 @@ function main() {} __memo_scope.recache(); return; } - }) as @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))); + })); }); - foo(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + foo(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/function-with-receiver.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/function-with-receiver.test.ts index dcc77c7d48951ccb541ea9e18e50991e4035e110..ef381afa07d4afcddd062e4534fb9e7a4ce66915 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/function-with-receiver.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/function-with-receiver.test.ts @@ -43,7 +43,8 @@ import { memo as memo } from "arkui.stateManagement.runtime"; function main() {} -@memo() function foo1(this: B, __memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string): void { +@Memo() +function foo1(this: B, __memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string): void { const __memo_scope = __memo_context.scope(((__memo_id) + (38567515)), 2); const __memo_parameter_this = __memo_scope.param(0, this), __memo_parameter_str = __memo_scope.param(1, str); if (__memo_scope.unchanged) { @@ -57,7 +58,8 @@ function main() {} } } -@memo() function foo2(this: B, __memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string): B { +@Memo() +function foo2(this: B, __memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string): B { const __memo_scope = __memo_context.scope(((__memo_id) + (167482260)), 2); const __memo_parameter_this = __memo_scope.param(0, this), __memo_parameter_str = __memo_scope.param(1, str); if (__memo_scope.unchanged) { @@ -68,7 +70,8 @@ function main() {} } class B { - @memo() public internal_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type): B { + @Memo() + public internal_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type): B { const __memo_scope = __memo_context.scope(((__memo_id) + (146437675)), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts index fbb23bd6b2f1c6e93fda61a0e21ccf6ae743e151..3c726f0cab6b932f6ff6790c1574e7032e724c2f 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts @@ -34,7 +34,8 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function bar(__memo_context: __memo_context_type, __memo_id: __memo_id_type, f?: (()=> void)): void { +@Memo() +function bar(__memo_context: __memo_context_type, __memo_id: __memo_id_type, f?: (()=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_f = __memo_scope.param(0, f); if (__memo_scope.unchanged) { @@ -46,8 +47,9 @@ function main() {} return; } } -function par(f?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} -@memo() function kar(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() f?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { +function par(f?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} +@Memo() +function kar(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() f?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_f = __memo_scope.param(0, f); if (__memo_scope.unchanged) { @@ -59,7 +61,7 @@ function par(f?: @memo() ((__memo_context: __memo_context_type, __memo_id: __mem return; } } -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -126,7 +128,8 @@ function par(f?: @memo() ((__memo_context: __memo_context_type, __memo_id: __mem } }); class A { - @memo() public foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, p?: (()=> void)): void { + @Memo() + public foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, p?: (()=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_p = __memo_scope.param(0, p); if (__memo_scope.unchanged) { @@ -138,8 +141,9 @@ class A { return; } } - public goo(@memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} - @memo() public koo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { + public goo(@Memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} + @Memo() + public koo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_p = __memo_scope.param(0, p); if (__memo_scope.unchanged) { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts index 68ca568de7cdfa2ed22b97a9bcc5bf7117abadc2..95ef7fa1d71c510612328deddc4d084ba6aa55d1 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts @@ -34,7 +34,7 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -45,7 +45,7 @@ function main() {} return; } }); -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg?: (()=> string)): void => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg?: (()=> string)): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts index 21ae14ad72cd55b4d03f3b52835ff45549adfae9..6237cc9edb1d396fded4915d542f4bcabe5be625 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts @@ -36,7 +36,8 @@ import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() function fullName(this: Person, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { +@Memo() +function fullName(this: Person, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 2); const __memo_parameter_this = __memo_scope.param(0, this), __memo_parameter_arg = __memo_scope.param(1, arg); if (__memo_scope.unchanged) { @@ -49,7 +50,8 @@ function main() {} } } -@memo() function foo(this: A, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { +@Memo() +function foo(this: A, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 2); const __memo_parameter_this = __memo_scope.param(0, this), __memo_parameter_arg = __memo_scope.param(1, arg); if (__memo_scope.unchanged) { @@ -62,7 +64,8 @@ function main() {} } } -@memo() function goo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, a: A, @memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { +@Memo() +function goo(__memo_context: __memo_context_type, __memo_id: __memo_id_type, a: A, @Memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 2); const __memo_parameter_a = __memo_scope.param(0, a), __memo_parameter_arg = __memo_scope.param(1, arg); if (__memo_scope.unchanged) { @@ -75,7 +78,7 @@ function main() {} } } -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -143,8 +146,8 @@ class A { public constructor() {} } -@memo() type F1 = ((this: A, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void); -@memo() type F2 = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, a: A, @memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void); +@Memo() type F1 = ((this: A, __memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void); +@Memo() type F2 = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, a: A, @Memo() arg?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void); `; function testMemoTransformer(this: PluginTestContext): void { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts index bac429889dfb8d0b389df5f2c243e0a4375eed71..2202e6ead077b311f28440995b297da320e87b32 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts @@ -33,7 +33,8 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} class Test { - @memo() public lambda_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + @Memo() + public lambda_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -45,7 +46,8 @@ class Test { return; } } - @memo() public lambda_arg_with_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string)=> string)) { + @Memo() + public lambda_arg_with_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string)=> string)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -57,7 +59,8 @@ class Test { return; } } - @memo() public memo_content(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + @Memo() + public memo_content(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_content = __memo_scope.param(0, content); if (__memo_scope.unchanged) { @@ -70,7 +73,8 @@ class Test { return; } } - @memo() public compute_test(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() arg1: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined), arg2: ((()=> void) | undefined), content: ((()=> void) | undefined)): void { + @Memo() + public compute_test(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() arg1: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined), arg2: ((()=> void) | undefined), content: ((()=> void) | undefined)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 3); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2), __memo_parameter_content = __memo_scope.param(2, content); if (__memo_scope.unchanged) { @@ -85,7 +89,8 @@ class Test { public constructor() {} } class Use { - @memo() public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts index 8886a3e30301945d0a6936572ee7de8f31561155..ad86c7013f6085be613156684846d2d158140e69 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts @@ -32,7 +32,7 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -62,7 +62,8 @@ function main() {} } }); class A { - @memo() public static $_invoke(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public static $_invoke(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -76,11 +77,12 @@ class A { public constructor() {} } class B { - public static $_invoke(@memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} + public static $_invoke(@Memo() p?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void {} public constructor() {} } class C { - @memo() public static $_instantiate(__memo_context: __memo_context_type, __memo_id: __memo_id_type, factory: (()=> C)): C { + @Memo() + public static $_instantiate(__memo_context: __memo_context_type, __memo_id: __memo_id_type, factory: (()=> C)): C { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_factory = __memo_scope.param(0, factory); if (__memo_scope.unchanged) { @@ -91,7 +93,7 @@ class C { public constructor() {} } class D { - public static $_instantiate(factory: (()=> D), @memo() content?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): D { + public static $_instantiate(factory: (()=> D), @Memo() content?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): D { return factory(); } public constructor() {} diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts index 23eb0d2d765b31fef94b2be8b42358ee69dee7ce..df68fc5f3beaa9bd4bb73657f4b86a582c5b75ee 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts @@ -34,7 +34,7 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -49,12 +49,14 @@ function main() {} } }); declare abstract class A { - @memo() public x(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void - public test_signature(@memo() arg1: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void), @memo() arg2: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined), @memo() arg3: ((((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) | (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int) | undefined)), @memo() x: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, y: ((z: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void))=> void)): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) + @Memo() + public x(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void + public test_signature(@Memo() arg1: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void), @Memo() arg2: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined), @Memo() arg3: ((((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) | (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> int) | undefined)), @Memo() x: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, y: ((z: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))=> void))=> void)): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) public constructor() {} } class AA extends A { - @memo() public x(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public x(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts index ba5b7c3f733a150da8fe106f2556902512762048..eee50c013766f73050557b50800940707e9db1be 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts @@ -39,9 +39,10 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id function main() {} export function __context(): __memo_context_type export function __id(): __memo_id_type -type MemoType = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); +type MemoType = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); class Test { - @memo() public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -52,7 +53,8 @@ class Test { return; } } - @memo() public internal_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public internal_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -64,7 +66,8 @@ class Test { return; } } - @memo() public method_with_internals(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public method_with_internals(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -78,7 +81,7 @@ class Test { } } public memo_lambda() { - @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -90,13 +93,14 @@ class Test { } }); } - @memo() public memo_variables(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public memo_variables(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - @memo() const f = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { + @Memo() const f = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; @@ -110,7 +114,7 @@ class Test { } return __memo_scope.recache(((123) + (__memo_parameter_x.value))); }); - const h = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { + const h = @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { return __memo_scope.cached; @@ -125,12 +129,13 @@ class Test { return; } } - @memo() public args_with_default_values(__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_1?: int, gensym%%_2?: (()=> int), gensym%%_3?: int, arg4?: int): void { - let arg1: int = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : (10 as int)); - let arg2: (()=> int) = (((gensym%%_2) !== (undefined)) ? gensym%%_2 : ((() => { + @Memo() + public args_with_default_values(__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_1?: int, gensym%%_2?: (()=> int), gensym%%_3?: int, arg4?: int): void { + let arg1: int = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : 10); + let arg2: (()=> int) = (((gensym%%_2) !== (undefined)) ? gensym%%_2 : (() => { return 20; - }) as (()=> int))); - let arg3: int = (((gensym%%_3) !== (undefined)) ? gensym%%_3 : (arg1 as int)); + })); + let arg3: int = (((gensym%%_3) !== (undefined)) ? gensym%%_3 : arg1); const __memo_scope = __memo_context.scope(((__memo_id) + ()), 4); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2), __memo_parameter_arg3 = __memo_scope.param(2, arg3), __memo_parameter_arg4 = __memo_scope.param(3, arg4); if (__memo_scope.unchanged) { @@ -144,7 +149,8 @@ class Test { return; } } - @memo() public optional_args(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1?: int, arg2?: (()=> int)) { + @Memo() + public optional_args(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1?: int, arg2?: (()=> int)) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 2); const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2); if (__memo_scope.unchanged) { @@ -160,7 +166,8 @@ class Test { return; } } - @memo() public type_alias(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: MemoType) { + @Memo() + public type_alias(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: MemoType) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts index f4466180ba17a630bdadef1c247676cc5b243917..86efde177df9ecf8ee2ab7842ddbfddb36b6d536 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts @@ -43,7 +43,8 @@ export function __id(): __memo_id_type @Retention({policy:"SOURCE"}) @interface memo_entry {} @Retention({policy:"SOURCE"}) @interface memo_skip {} class Test { - @memo() public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -54,7 +55,8 @@ class Test { return; } } - @memo() public string_method_with_return(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string): string { + @Memo() + public string_method_with_return(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string): string { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -62,7 +64,8 @@ class Test { } return __memo_scope.recache(__memo_parameter_arg.value); } - @memo() public method_with_type_parameter(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T): T { + @Memo() + public method_with_type_parameter(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T): T { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -70,14 +73,17 @@ class Test { } return __memo_scope.recache(__memo_parameter_arg.value); } - @memo_intrinsic() public intrinsic_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): int { + @memo_intrinsic() + public intrinsic_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): int { return 0; } - @memo_intrinsic() public intrinsic_method_with_this(__memo_context: __memo_context_type, __memo_id: __memo_id_type): int { + @memo_intrinsic() + public intrinsic_method_with_this(__memo_context: __memo_context_type, __memo_id: __memo_id_type): int { this.void_method(__memo_context, ((__memo_id) + ())); return 0; } - @memo_entry() public memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> R)): R { + @memo_entry() + public memoEntry(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() entry: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> R)): R { const getContext = (() => { return __memo_context; }); @@ -90,7 +96,8 @@ class Test { return entry(__memo_context, ((__memo_id) + ())); } } - @memo() public memo_skip_args(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, @memo_skip() arg2: string, @memo_skip() arg3: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): string { + @Memo() + public memo_skip_args(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1: number, @memo_skip() arg2: string, @memo_skip() arg3: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): string { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg1 = __memo_scope.param(0, arg1); if (__memo_scope.unchanged) { @@ -103,7 +110,8 @@ class Test { public constructor() {} } class Use { - @memo() public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts index a4487b6546df8c4c74e1af99c11d2b2ab7758124..78045f3267207e7d288ca610a3e2e282ac5e6912 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts @@ -40,7 +40,8 @@ class A { public constructor() {} } class Test { - @memo() public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -51,7 +52,8 @@ class Test { return; } } - @memo() public a_method_with_implicit_return_type(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public a_method_with_implicit_return_type(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -62,7 +64,8 @@ class Test { return; } } - @memo() public void_method_with_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string) { + @Memo() + public void_method_with_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -74,7 +77,8 @@ class Test { return; } } - @memo() public void_method_with_return(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string) { + @Memo() + public void_method_with_return(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: string) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -86,7 +90,8 @@ class Test { return; } } - @memo() public static static_method_with_type_parameter(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T): void { + @Memo() + public static static_method_with_type_parameter(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: T): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -98,7 +103,8 @@ class Test { return; } } - @memo() public obj_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: A) { + @Memo() + public obj_arg(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: A) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_arg = __memo_scope.param(0, arg); if (__memo_scope.unchanged) { @@ -113,7 +119,8 @@ class Test { public constructor() {} } class Use { - @memo() public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public test(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts index a80aa797266c6c26ef40c163382904d07bd96e62..685e27c37e82203ffefeafefa1da19f4bc1c8a14 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts @@ -35,7 +35,7 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -60,10 +60,10 @@ function main() {} } }); interface A { - ${dumpGetterSetter(GetSetDumper.BOTH, 'a', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('memo')], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'a', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('Memo')], [], false)} } class AA { - @memo() public a: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined); + @Memo() public a: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined); public constructor(arg: (A | undefined)) { this.a = ({let gensym%%_ = arg; (((gensym%%_) == (null)) ? undefined : gensym%%_.a)}); @@ -71,7 +71,8 @@ class AA { public constructor() { this(undefined); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts index 066fb882923eddada0a9c3ab724521bee33435c4..d31159ff4b32d8ef3259845861aa97715a274ec1 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts @@ -36,9 +36,9 @@ import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} class A { public arg: (()=> void); - @memo() public memo_arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - @memo() public memo_optional_arg?: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined); - @memo() public memo_union_arg: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + @Memo() public memo_arg: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); + @Memo() public memo_optional_arg?: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined); + @Memo() public memo_union_arg: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -49,7 +49,7 @@ class A { return; } }); - public arg_memo_type: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); + public arg_memo_type: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); public constructor() { this.arg = (() => {}); this.memo_arg = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { @@ -75,7 +75,8 @@ class A { } }); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; diff --git a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts index 3998a4e4c8e83b5e87d4017d5765d679d3887960..4de371f49addec2839005c4c96e2f24e8ad0f758 100644 --- a/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts +++ b/ui2abc/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts @@ -33,7 +33,7 @@ const expectedScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; import { memo as memo } from \"arkui.stateManagement.runtime\"; function main() {} -@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -82,10 +82,10 @@ function main() {} }); interface A { ${dumpGetterSetter(GetSetDumper.BOTH, 'arg', '(()=> void)', [], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_arg', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('memo')], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_optional_arg', '(((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_union_arg', '(((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)', [dumpAnnotation('memo')], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'arg_memo_type', '@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_arg', '((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [dumpAnnotation('Memo')], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_optional_arg', '(((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'memo_union_arg', '(((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)', [dumpAnnotation('Memo')], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'arg_memo_type', '@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)', [], [], false)} } `; diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts index abb6945f6e321d176568612ec3f91908c5944aca..8397632234b07ce0d2331589e4a3506f488d2a86 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animatable-extend-basic.test.ts @@ -19,7 +19,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -41,7 +41,7 @@ const pluginTester = new PluginTester('test basic animatableExtend transform', b const expectedScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -73,16 +73,17 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct AnimatablePropertyExample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_AnimatablePropertyExample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_AnimatablePropertyExample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_AnimatablePropertyExample | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("AnimatableProperty", undefined).animationStart({ duration: 2000, curve: Curve.Ease, @@ -102,11 +103,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { AnimatablePropertyExample._instantiateImpl(undefined, (() => { return new AnimatablePropertyExample(); }), undefined, undefined, undefined); @@ -132,7 +137,7 @@ function testAnimatableExtendTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic animation transform', - [animatableExtendTransform, uiNoRecheck, recheck], + [animatableExtendTransform, beforeUINoRecheck, uiNoRecheck, recheck], { checked: [testAnimatableExtendTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts index b1cfd33da42f2269bc97ca18b714977e9038cd5f..8065d8a334ce956687e234f1d7e3c144e581df24 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -40,7 +40,7 @@ const pluginTester = new PluginTester('test basic animation transform', buildCon const expectedScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -72,16 +72,17 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct AnimatablePropertyExample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_AnimatablePropertyExample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_AnimatablePropertyExample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_AnimatablePropertyExample | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("AnimatableProperty", undefined).animationStart({ duration: 2000, curve: Curve.Ease, @@ -101,11 +102,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { AnimatablePropertyExample._instantiateImpl(undefined, (() => { return new AnimatablePropertyExample(); }), undefined, undefined, undefined); @@ -132,7 +137,7 @@ function testAnimationTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic animation transform', - [animationTransform, uiNoRecheck, recheck], + [animationTransform, beforeUINoRecheck, uiNoRecheck, recheck], { checked: [testAnimationTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/block-in-switch-case.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/block-in-switch-case.test.ts index 714c4a2693001a4d631f1ccdada59ea2840ad382..db69f9de2e2061875a4fbf1a8bc8e73cc1f4766c 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/block-in-switch-case.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/block-in-switch-case.test.ts @@ -19,7 +19,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -43,7 +43,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -53,7 +53,7 @@ import { Text as Text, Column as Column, Component as Component } from "@ohos.ar function main() {} @Component() final struct SwitchCase extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = ((({let gensym___83257243 = initializers; (((gensym___83257243) == (null)) ? undefined : gensym___83257243.num)})) ?? (2)); } @@ -70,28 +70,29 @@ function main() {} this.__backing_num = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { switch (this.num) { case 0: { break; } case 1: { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); })); } case 2: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); @@ -99,24 +100,24 @@ function main() {} })); } case 3: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); } })); break; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); } case 4: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); @@ -126,9 +127,9 @@ function main() {} break; } case 5: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); @@ -137,7 +138,7 @@ function main() {} break; } case 6: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { return; } @@ -145,10 +146,10 @@ function main() {} break; } case 7: { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { return; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("111", undefined).applyAttributesFinish(); return; }), undefined); @@ -161,7 +162,7 @@ function main() {} } } })); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("hello world", undefined).applyAttributesFinish(); return; }), undefined); @@ -169,7 +170,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_SwitchCase { @@ -188,7 +192,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -198,7 +202,7 @@ import { Text as Text, Column as Column, Component as Component } from "@ohos.ar function main() {} @Component() final struct SwitchCase extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_num = ((({let gensym___83257243 = initializers; (((gensym___83257243) == (null)) ? undefined : gensym___83257243.num)})) ?? (2)); } @@ -215,13 +219,14 @@ function main() {} this.__backing_num = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (261239291)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -233,13 +238,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (147868395)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + (186113)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + (186113)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (186336799)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -250,13 +255,13 @@ function main() {} break; } case 1: { - ConditionBranch(__memo_context, ((__memo_id) + (27357263)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (27357263)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (78642435)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -276,14 +281,14 @@ function main() {} })); } case 2: { - ConditionBranch(__memo_context, ((__memo_id) + (220977109)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (220977109)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (91459184)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } { - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -304,14 +309,14 @@ function main() {} })); } case 3: { - ConditionBranch(__memo_context, ((__memo_id) + (143235624)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (143235624)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (214575380)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } { - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -331,7 +336,7 @@ function main() {} } })); break; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -346,14 +351,14 @@ function main() {} }), undefined); } case 4: { - ConditionBranch(__memo_context, ((__memo_id) + (7513933)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (7513933)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (235688754)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } { - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -372,14 +377,14 @@ function main() {} break; } case 5: { - ConditionBranch(__memo_context, ((__memo_id) + (58475451)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (58475451)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (257250368)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } { - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -401,7 +406,7 @@ function main() {} break; } case 6: { - ConditionBranch(__memo_context, ((__memo_id) + (60292460)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (60292460)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (21099142)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -414,7 +419,7 @@ function main() {} break; } case 7: { - ConditionBranch(__memo_context, ((__memo_id) + (34940192)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + (34940192)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (15961624)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -422,7 +427,7 @@ function main() {} } { return; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -452,7 +457,7 @@ function main() {} return; } })); - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -477,7 +482,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_SwitchCase { @@ -493,7 +501,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test block statement in switch case', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/else-if-in-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/else-if-in-content.test.ts index d7fe512a388448edc4f6a5b10f2439729c38bd15..54191d80a14990699dad3a93fd366e3bad14df40 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/else-if-in-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/else-if-in-content.test.ts @@ -19,7 +19,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -42,7 +42,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -50,27 +50,28 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct ElseIf extends CustomComponent { - public __initializeStruct(initializers: (__Options_ElseIf | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ElseIf | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ElseIf | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => {})); + ConditionBranch(@Memo() (() => {})); } else { if (false) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("elseIf 1", undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("else 1", undefined).applyAttributesFinish(); return; }), undefined); @@ -78,22 +79,22 @@ function main() {} } } })); - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (false) { - ConditionBranch(@memo() (() => {})); + ConditionBranch(@Memo() (() => {})); } else { - ConditionBranch(@memo() (() => { - ConditionScope(@memo() (() => { + ConditionBranch(@Memo() (() => { + ConditionScope(@Memo() (() => { if (false) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("elseIf 2", undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("else 2", undefined).applyAttributesFinish(); return; }), undefined); @@ -106,6 +107,10 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() export interface __Options_ElseIf { } @@ -120,7 +125,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -128,15 +133,16 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct ElseIf extends CustomComponent { - public __initializeStruct(initializers: (__Options_ElseIf | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ElseIf | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ElseIf | undefined)): void {} - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -148,20 +154,20 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -174,13 +180,13 @@ function main() {} })); } else { if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -199,13 +205,13 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -230,14 +236,14 @@ function main() {} return; } })); - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -249,26 +255,26 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -287,13 +293,13 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -339,6 +345,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_ElseIf { } @@ -350,7 +360,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test else-if condition branch', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-break-in-nested-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-break-in-nested-content.test.ts index c804bbe33c656d677a443252b5e53ae65cd017e9..8f16a8fd1a53c75afb7334908b5c9b1dc7935798 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-break-in-nested-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-break-in-nested-content.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -41,7 +41,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -50,32 +50,33 @@ import { Component as Component, Column as Column, Text as Text } from \"@ohos.a import hilog from \"@ohos.hilog\"; function main() {} @Component() final struct A extends CustomComponent { - public __initializeStruct(initializers: (__Options_A | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_A | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_A | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), @Memo() (() => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), @Memo() (() => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), @Memo() (() => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (false) { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { hilog.info(0x0000, \"very inside\", \"1\"); })); return; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("1", undefined).applyAttributesFinish(); return; }), undefined); @@ -84,11 +85,11 @@ function main() {} })); })); })); - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { hilog.info(0x0000, \"outside column\", \"2\"); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("1", undefined).applyAttributesFinish(); return; }), undefined); @@ -98,6 +99,10 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() export interface __Options_A { } @@ -112,7 +117,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -121,15 +126,16 @@ import { Component as Component, Column as Column, Text as Text } from \"@ohos.a import hilog from \"@ohos.hilog\"; function main() {} @Component() final struct A extends CustomComponent { - public __initializeStruct(initializers: (__Options_A | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_A | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_A | undefined)): void {} - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -141,13 +147,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -159,13 +165,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -177,13 +183,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -195,20 +201,20 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -220,8 +226,11 @@ function main() {} return; } })); - return; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + { + __memo_scope.recache(); + return; + } + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -255,21 +264,21 @@ function main() {} return; } })); - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } hilog.info(0x0000, \"outside column\", \"2\"); - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -304,6 +313,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_A { } @@ -315,7 +328,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test if condition branch break statements', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-else-in-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-else-in-content.test.ts index d89f9f6427a1f5f9cbea26374fe087147fa6b012..df84538615d4e59733e5c77435c376af4c350bbb 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-else-in-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-else-in-content.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -41,7 +41,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -49,35 +49,36 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct IfElse extends CustomComponent { - public __initializeStruct(initializers: (__Options_IfElse | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_IfElse | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_IfElse | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - ConditionScope(@memo() (() => { + ConditionBranch(@Memo() (() => { + ConditionScope(@Memo() (() => { if (false) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("if-if", undefined).applyAttributesFinish(); return; }), undefined); })); } else { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("if-elseIf", undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("if-else", undefined).applyAttributesFinish(); return; }), undefined); @@ -88,34 +89,38 @@ function main() {} })); } else { if (false) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("elseIf", undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("else", undefined).applyAttributesFinish(); return; }), undefined); })); return; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("after-return", undefined).applyAttributesFinish(); return; }), undefined); } } })); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("hello world", undefined).applyAttributesFinish(); return; }), undefined); })); } public constructor() {} + + static { + + } } @Component() export interface __Options_IfElse { } @@ -130,7 +135,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -138,15 +143,16 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct IfElse extends CustomComponent { - public __initializeStruct(initializers: (__Options_IfElse | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_IfElse | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_IfElse | undefined)): void {} - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -158,39 +164,39 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -210,13 +216,13 @@ function main() {} })); } else { if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -235,13 +241,13 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -273,13 +279,13 @@ function main() {} })); } else { if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -298,13 +304,13 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -322,8 +328,11 @@ function main() {} return; } })); - return; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + { + __memo_scope.recache(); + return; + } + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -343,7 +352,7 @@ function main() {} return; } })); - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -367,6 +376,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_IfElse { } @@ -378,7 +391,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test if-else', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-in-switch-in-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-in-switch-in-content.test.ts index a6740db62f58be82b3d3074c78171dda884f636a..81508615aa6999c7dcc8f036be0138a2ef1a11e3 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-in-switch-in-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/if-in-switch-in-content.test.ts @@ -19,7 +19,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -43,7 +43,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -51,7 +51,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct IfInSwitch extends CustomComponent { - public __initializeStruct(initializers: (__Options_IfInSwitch | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_IfInSwitch | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -63,35 +63,36 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { switch (this.num) { case \"-1\": { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { { - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 1", undefined).applyAttributesFinish(); return; }), undefined); })); } else { if (false) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 2", undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 3", undefined).applyAttributesFinish(); return; }), undefined); @@ -103,11 +104,11 @@ function main() {} })); } case \"2\": { - ConditionBranch(@memo() (() => { - ConditionScope(@memo() (() => { + ConditionBranch(@Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 4", undefined).applyAttributesFinish(); return; }), undefined); @@ -121,6 +122,10 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() export interface __Options_IfInSwitch { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -138,7 +143,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -146,7 +151,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct IfInSwitch extends CustomComponent { - public __initializeStruct(initializers: (__Options_IfInSwitch | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_IfInSwitch | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -158,13 +163,14 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -176,13 +182,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -190,27 +196,27 @@ function main() {} } switch (this.num) { case \"-1\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } { - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -230,13 +236,13 @@ function main() {} })); } else { if (false) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -255,13 +261,13 @@ function main() {} } })); } else { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -294,26 +300,26 @@ function main() {} })); } case \"2\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -360,6 +366,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_IfInSwitch { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -374,7 +384,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test if conditions in switch-case', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/non-builder-within-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/non-builder-within-builder.test.ts index 5e911210f29a3049cfedf1f0ad886abc2f423520..32004fe33bad0a58213825c8b31f440338858b3c 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/non-builder-within-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/non-builder-within-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -42,17 +42,20 @@ const parsedTransform: Plugins = { const expectedUIScript: string = ` import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; import { Component as Component, Builder as Builder } from \"@ohos.arkui.component\"; function main() {} -@memo() function TestComponent(@MemoSkip() init: TestInitCallback, @MemoSkip() update: TestUpdateCallback): void {} +@Builder() +@Memo() +function TestComponent(@MemoSkip() init: TestInitCallback, @MemoSkip() update: TestUpdateCallback): void {} type TestInitCallback = (()=> void); type TestUpdateCallback = (()=> void); @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() { + @Memo() + public build() { TestComponent((() => { if (true) { } @@ -62,6 +65,10 @@ type TestUpdateCallback = (()=> void); })); } public constructor() {} + + static { + + } } @Component() export interface __Options_MyStateSample { } @@ -73,7 +80,7 @@ function testUITransformer(this: PluginTestContext): void { pluginTester.run( 'test no conditionScope in non-@Builder function', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-case-in-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-case-in-content.test.ts index e830f4014ff385c5c49878deedbcbd6010b5172d..b36401248676b4311d1a3c62154614482cb34287 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-case-in-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-case-in-content.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -42,7 +42,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -50,7 +50,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct SwitchCase extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -62,50 +62,51 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { switch (this.num) { case \"0\": { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 0", undefined).applyAttributesFinish(); return; }), undefined); })); } case \"1\": { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 1", undefined).applyAttributesFinish(); return; }), undefined); })); break; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("after break", undefined).applyAttributesFinish(); return; }), undefined); } case \"2\": { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 2", undefined).applyAttributesFinish(); return; }), undefined); })); return; - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("after return", undefined).applyAttributesFinish(); return; }), undefined); } default: { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("default", undefined).applyAttributesFinish(); return; }), undefined); @@ -113,13 +114,17 @@ function main() {} } } })); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("hello world", undefined).applyAttributesFinish(); return; }), undefined); })); } public constructor() {} + + static { + + } } @Component() export interface __Options_SwitchCase { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -137,7 +142,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -145,7 +150,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct SwitchCase extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchCase | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -157,13 +162,14 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -175,13 +181,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -189,13 +195,13 @@ function main() {} } switch (this.num) { case \"0\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -215,13 +221,13 @@ function main() {} })); } case \"1\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -240,7 +246,7 @@ function main() {} } })); break; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -255,13 +261,13 @@ function main() {} }), undefined); } case \"2\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -280,7 +286,7 @@ function main() {} } })); return; - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -295,13 +301,13 @@ function main() {} }), undefined); } default: { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -326,7 +332,7 @@ function main() {} return; } })); - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -350,6 +356,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_SwitchCase { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -364,7 +374,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test switch-case', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-in-if-in-content.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-in-if-in-content.test.ts index 7062c2eae5498f713f3d5aee26e79bf1a4f0942d..2ffecc004a28db2454065ea6977653bd92380de8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-in-if-in-content.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/switch-in-if-in-content.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -42,7 +42,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -50,7 +50,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct SwitchInIf extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchInIf | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchInIf | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -62,19 +62,20 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - ConditionScope(@memo() (() => { + ConditionBranch(@Memo() (() => { + ConditionScope(@Memo() (() => { switch (this.num) { case \"0\": { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("case 0", undefined).applyAttributesFinish(); return; }), undefined); @@ -88,6 +89,10 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() export interface __Options_SwitchInIf { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -105,7 +110,7 @@ import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -113,7 +118,7 @@ import { CustomComponent as CustomComponent } from \"arkui.component.customCompo import { Text as Text, Column as Column, Component as Component } from \"@ohos.arkui.component\"; function main() {} @Component() final struct SwitchInIf extends CustomComponent { - public __initializeStruct(initializers: (__Options_SwitchInIf | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SwitchInIf | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_num = ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.num)})) ?? (\"1\")); } @@ -125,13 +130,14 @@ function main() {} public set num(value: string) { this.__backing_num = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -143,26 +149,26 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -170,13 +176,13 @@ function main() {} } switch (this.num) { case \"0\": { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -223,6 +229,10 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_SwitchInIf { ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(string | undefined)')} @@ -237,7 +247,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test switch-statement in if', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/with-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/with-builder.test.ts index f86a5a701fc0e50c4a0eae20a2610bbcc7d8cff5..2f9a4d8e32d8922fd6458e308df8da95c2d31d44 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/with-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/condition-scope/with-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -44,18 +44,20 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder } from \"@ohos.arkui.component\"; const wBuilder = wrapBuilder(ParamBuilder); function main() {} -@memo() function MyBuilder(): void { - ConditionScope(@memo() (() => { +@Builder() +@Memo() +function MyBuilder(): void { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within Builder function", undefined).applyAttributesFinish(); return; }), undefined); @@ -63,29 +65,32 @@ function main() {} } })); } -@memo() function ParamBuilder(@Builder() @memo() @MemoSkip() gensym%%_?: (()=> void)): void { - let param: (()=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : ((() => { - ConditionScope(@memo() (() => { +@Builder() +@Memo() +function ParamBuilder(@Builder() @Memo() @MemoSkip() gensym%%_?: (()=> void)): void { + let param: (()=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within Builder parameter", undefined).applyAttributesFinish(); return; }), undefined); })); } })); - }) as (()=> void))); + })); param(); } @Component() final struct MyStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStruct | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStruct | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStruct | undefined)): void {} - @memo() public myBuilderMethod() { - ConditionScope(@memo() (() => { + @Memo() + public myBuilderMethod() { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within Builder method", undefined).applyAttributesFinish(); return; }), undefined); @@ -93,16 +98,17 @@ function main() {} } })); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { wBuilder.builder(@Builder() (() => { - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("with Builder lambda", undefined).applyAttributesFinish(); return; }), undefined); @@ -113,11 +119,11 @@ function main() {} Child._instantiateImpl(undefined, (() => { return new Child(); }), { - myBuilderParam: @memo() (() => { - ConditionScope(@memo() (() => { + myBuilderParam: @Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within Builder property", undefined).applyAttributesFinish(); return; }), undefined); @@ -131,15 +137,19 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_myBuilderParam = ((((({let gensym___ = initializers; - (((gensym___) == (null)) ? undefined : gensym___.myBuilderParam)})) ?? (content))) ?? ((() => { - ConditionScope(@memo() (() => { + (((gensym___) == (null)) ? undefined : gensym___.myBuilderParam)})) ?? (content))) ?? (@Memo() (() => { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within BuilderParam property", undefined).applyAttributesFinish(); return; }), undefined); @@ -149,18 +159,19 @@ function main() {} }))); } public __updateStruct(initializers: (__Options_Child | undefined)): void {} - private __backing_myBuilderParam?: @memo() (()=> void); - public get myBuilderParam(): @memo() (()=> void) { + private __backing_myBuilderParam?: @Memo() (()=> void); + public get myBuilderParam(): @Memo() (()=> void) { return this.__backing_myBuilderParam!; } - public set myBuilderParam(value: @memo() (()=> void)) { + public set myBuilderParam(value: @Memo() (()=> void)) { this.__backing_myBuilderParam = value; } - @memo() public build() { - ConditionScope(@memo() (() => { + @Memo() + public build() { + ConditionScope(@Memo() (() => { if (true) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("within struct build", undefined).applyAttributesFinish(); return; }), undefined); @@ -169,11 +180,15 @@ function main() {} })); } public constructor() {} + + static { + + } } @Component() export interface __Options_MyStruct { } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'myBuilderParam', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'myBuilderParam', '(@Memo() (()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_myBuilderParam', '(boolean | undefined)')} } `; @@ -189,33 +204,35 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; import { ConditionScope as ConditionScope } from \"arkui.component.builder\"; import { ConditionBranch as ConditionBranch } from \"arkui.component.builder\"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder } from \"@ohos.arkui.component\"; const wBuilder = wrapBuilder(ParamBuilder); function main() {} -@memo() function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { +@Builder() +@Memo() +function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -244,27 +261,29 @@ function main() {} return; } } -@memo() function ParamBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Builder() @memo() @MemoSkip() gensym%%_?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { - let param: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { +@Builder() +@Memo() +function ParamBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Builder() @Memo() @MemoSkip() gensym%%_?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { + let param: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) = (((gensym%%_) !== (undefined)) ? gensym%%_ : ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -292,7 +311,7 @@ function main() {} __memo_scope.recache(); return; } - }) as ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void))); +})); const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -305,28 +324,29 @@ function main() {} } } @Component() final struct MyStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStruct | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStruct | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStruct | undefined)): void {} - @memo() public myBuilderMethod(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public myBuilderMethod(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -355,13 +375,14 @@ function main() {} return; } } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -373,7 +394,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -385,20 +406,20 @@ function main() {} __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -430,26 +451,26 @@ function main() {} Child._instantiateImpl(__memo_context, ((__memo_id) + ()), undefined, (() => { return new Child(); }), { - myBuilderParam: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + myBuilderParam: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -492,30 +513,34 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_myBuilderParam = ((((({let gensym___ = initializers; - (((gensym___) == (null)) ? undefined : gensym___.myBuilderParam)})) ?? (content))) ?? (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + (((gensym___) == (null)) ? undefined : gensym___.myBuilderParam)})) ?? (content))) ?? (@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -546,33 +571,34 @@ function main() {} }))); } public __updateStruct(initializers: (__Options_Child | undefined)): void {} - private __backing_myBuilderParam?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - public get myBuilderParam(): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { + private __backing_myBuilderParam?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); + public get myBuilderParam(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { return this.__backing_myBuilderParam!; } - public set myBuilderParam(value: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + public set myBuilderParam(value: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { this.__backing_myBuilderParam = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (true) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -602,11 +628,15 @@ function main() {} } } public constructor() {} + + static { + + } } @Component() export interface __Options_MyStruct { } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'myBuilderParam', '(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'myBuilderParam', '(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_myBuilderParam', '(boolean | undefined)')} } `; @@ -617,7 +647,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test conditionScope within @Builder or @BuilderParam', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts index 244c55784e8122a26ef0678750380472c16bf33b..385fff03730963468e5e30c99e1d54608fc2ffba 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -53,14 +53,15 @@ import { CustomComponent as CustomComponent } from "arkui.component.customCompon import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; @Component() final struct CustomContainer extends CustomComponent { - @Builder() public closerBuilder() {} + @Builder() + public closerBuilder() {} @BuilderParam() public closer: (()=> void) = this.closerBuilder; public build() {} public constructor() {} - + } @Component() final struct CustomContainerUser extends CustomComponent { @@ -80,7 +81,7 @@ import { Text as Text, Column as Column, Component as Component, Builder as Buil } public constructor() {} - + } @Component() export interface __Options_CustomContainer { @@ -109,7 +110,7 @@ import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -121,49 +122,55 @@ function main() {} @Component() final struct CustomContainer extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomContainer | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomContainer | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_closer = ((((({let gensym___38813563 = initializers; (((gensym___38813563) == (null)) ? undefined : gensym___38813563.closer)})) ?? (content))) ?? (this.closerBuilder)); } public __updateStruct(initializers: (__Options_CustomContainer | undefined)): void {} + + @Memo() + public closerBuilder() {} - private __backing_closer?: @memo() (()=> void); + private __backing_closer?: @Memo() (()=> void); - public get closer(): @memo() (()=> void) { + public get closer(): @Memo() (()=> void) { return this.__backing_closer!; } - public set closer(value: @memo() (()=> void)) { + public set closer(value: @Memo() (()=> void)) { this.__backing_closer = value; } - @memo() public closerBuilder() {} - - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() final struct CustomContainerUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomContainerUser | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_CustomContainerUser | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_CustomContainerUser | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { CustomContainer._instantiateImpl(undefined, (() => { return new CustomContainer(); - }), undefined, undefined, @memo() (() => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), undefined, undefined, @Memo() (() => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("hello", undefined).applyAttributesFinish(); return; }), undefined); @@ -171,15 +178,15 @@ function main() {} })); CustomContainer._instantiateImpl(undefined, (() => { return new CustomContainer(); - }), {}, undefined, @memo() (() => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), {}, undefined, @Memo() (() => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => {})); + }), @Memo() (() => {})); })); CustomContainer._instantiateImpl(undefined, (() => { return new CustomContainer(); - }), undefined, undefined, @memo() (() => {})); + }), undefined, undefined, @Memo() (() => {})); CustomContainer._instantiateImpl(undefined, (() => { return new CustomContainer(); }), undefined, undefined, undefined); @@ -187,11 +194,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_CustomContainer { - ${dumpGetterSetter(GetSetDumper.BOTH, 'closer', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'closer', '(@Memo() (()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_closer', '(boolean | undefined)')} } @@ -207,7 +217,7 @@ function testCustomComponentTransformer(this: PluginTestContext): void { pluginTester.run( 'test custom component call transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { parsed: [testParedTransformer], 'checked:ui-no-recheck': [testCustomComponentTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/custom-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/custom-builder.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f1146b83b1707cf14b8f988681d0fb702b26bc8 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/custom-builder.test.ts @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; +const INNER_COMPONENT_DIR_PATH: string = 'inner-component'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve( + getRootPath(), + MOCK_ENTRY_DIR_PATH, + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + 'custom-builder.ets' + ), +]; + +const pluginTester = new PluginTester('test passing CustomBuilder to component', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsedTransform', + parsed: uiTransform().parsed, +}; + +const expectedUIScript: string = ` +function main() {} +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + @Memo() + public itemHead(@MemoSkip() text: string) { + TextImpl(@Memo() ((instance: TextAttribute): void => { + instance.setTextOptions(text, undefined).fontSize(20).backgroundColor(0xAABBCC).applyAttributesFinish(); + return; + }), undefined); + } + + @Memo() + public itemFoot(@MemoSkip() num: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { + instance.setTextOptions(\"Foot\", undefined).fontSize(16).backgroundColor(0xAABBCC).applyAttributesFinish(); + return; + }), undefined); + } + + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { + instance.setColumnOptions(undefined).applyAttributesFinish(); + return; + }), @Memo() (() => { + ListItemGroupImpl(@Memo() ((instance: ListItemGroupAttribute): void => { + instance.setListItemGroupOptions({ + header: @Memo() (() => { + this.itemHead(\"Head\"); + }), + footer: ((() => { + this.itemFoot(100); + }) as CustomBuilder), + }).applyAttributesFinish(); + return; + }), @Memo() (() => {})); + })); + } + public constructor() {} + static { + } +} + +@Component() export interface __Options_MyStateSample { +} +`; + +function testUITransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIScript)); +} + +const expectedMemoScript: string = ` +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "arkui.incremental.runtime.state"; + +import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; + +import { ColumnImpl as ColumnImpl } from "arkui.component.column"; + +import { ListItemGroupAttribute as ListItemGroupAttribute } from "arkui.component.listItemGroup"; + +import { ListItemGroupImpl as ListItemGroupImpl } from "arkui.component.listItemGroup"; + +import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; + +import { Memo as Memo } from "arkui.incremental.annotation"; + +import { TextAttribute as TextAttribute } from "arkui.component.text"; + +import { TextImpl as TextImpl } from "arkui.component.text"; + +import { Memo as Memo } from "arkui.incremental.annotation"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, Builder as Builder, ListItemGroup as ListItemGroup, CustomBuilder as CustomBuilder } from "@ohos.arkui.component"; + +function main() {} + + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + @Memo() + public itemHead(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() text: string) { + const __memo_scope = __memo_context.scope(((__memo_id) + (199087787)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + TextImpl(__memo_context, ((__memo_id) + (175145513)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (47330804)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setTextOptions(text, undefined).fontSize(20).backgroundColor(0xAABBCC).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), undefined); + { + __memo_scope.recache(); + return; + } + } + + @Memo() + public itemFoot(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() num: number) { + const __memo_scope = __memo_context.scope(((__memo_id) + (137467525)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + TextImpl(__memo_context, ((__memo_id) + (211301233)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (137225318)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setTextOptions("Foot", undefined).fontSize(16).backgroundColor(0xAABBCC).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), undefined); + { + __memo_scope.recache(); + return; + } + } + + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + const __memo_scope = __memo_context.scope(((__memo_id) + (145073445)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ColumnImpl(__memo_context, ((__memo_id) + (262314519)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setColumnOptions(undefined).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (78055758)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ListItemGroupImpl(__memo_context, ((__memo_id) + (136716185)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ListItemGroupAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + (213687742)), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setListItemGroupOptions({ + header: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (218979098)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + this.itemHead(__memo_context, ((__memo_id) + (76711614)), "Head"); + { + __memo_scope.recache(); + return; + } + }), + footer: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + this.itemFoot(__memo_context, ((__memo_id) + (223657391)), 100); + { + __memo_scope.recache(); + return; + } + }) as CustomBuilder), + }).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + } + + public constructor() {} + + static { + + } +} + +@Component() export interface __Options_MyStateSample { + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedMemoScript)); +} + +pluginTester.run( + 'test passing CustomBuilder to component', + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testUITransformer], + 'checked:memo-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/multi-component-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/multi-component-builder.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b61c80293ba037b5f457175a59ecda8c97754378 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/multi-component-builder.test.ts @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; +const INNER_COMPONENT_DIR_PATH: string = 'inner-component'; +const UTIL_DIR_PATH: string = 'utils'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve( + getRootPath(), + MOCK_ENTRY_DIR_PATH, + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + 'multi-component-builder.ets' + ), +]; + +const utilExternalSourceName = [ + buildConfig.packageName, + MOCK_ENTRY_DIR_PATH.replaceAll('/', '.'), + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + UTIL_DIR_PATH, + 'fake-multi-component' +].join('.'); + +const pluginTester = new PluginTester('test multiple different @ComponentBuilder', buildConfig); + +const parsedTransform: Plugins = { + name: 'multi-component-builder', + parsed: uiTransform().parsed, +}; + +const expectedUIScript: string = ` +import { FakeComponentCAttribute as FakeComponentCAttribute } from \"${utilExternalSourceName}\"; +import { FakeComponentCImpl as FakeComponentCImpl } from \"${utilExternalSourceName}\"; +import { FakeComponentBAttribute as FakeComponentBAttribute } from \"${utilExternalSourceName}\"; +import { FakeComponentBImpl as FakeComponentBImpl } from \"${utilExternalSourceName}\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; +import { FakeComponentAAttribute as FakeComponentAAttribute } from \"${utilExternalSourceName}\"; +import { FakeComponentAImpl as FakeComponentAImpl } from \"${utilExternalSourceName}\"; +import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; +import { PageLifeCycle as PageLifeCycle } from \"arkui.component.customComponent\"; +import { EntryPoint as EntryPoint } from \"arkui.component.customComponent\"; +import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; +import { Entry as Entry, Component as Component } from \"arkui.component.customComponent\"; +import { FakeComponentA as FakeComponentA, FakeComponentB as FakeComponentB, FakeComponentC as FakeComponentC } from \"./utils/fake-multi-component\"; + +function main() {} + __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ + bundleName: \"com.example.mock\", + moduleName: \"entry\", + pagePath: \"../../../builder-lambda/inner-component/multi-component-builder\", + pageFullPath: \"test/demo/mock/builder-lambda/inner-component/multi-component-builder\", + integratedHsp: \"false\", +} as NavInterface)); + +@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct A extends CustomComponent implements PageLifeCycle { + public __initializeStruct(initializers: (__Options_A | undefined), @Memo() content: ((()=> void) | undefined)): void {} + public __updateStruct(initializers: (__Options_A | undefined)): void {} + @Memo() + public build() { + FakeComponentAImpl(@Memo() ((instance: FakeComponentAAttribute): void => { + instance.setFakeComponentAOptions(\"fake-component\"); + return; + }), undefined); + FakeComponentBImpl(@Memo() ((instance: FakeComponentBAttribute): void => { + instance.setFakeComponentBOptions({}); + return; + }), undefined); + FakeComponentCImpl(@Memo() ((instance: FakeComponentCAttribute): void => { + instance.setFakeComponentCOptions(); + return; + }), @Memo() (() => {})); + } + public constructor() {} + + static { + + } +} + +class __EntryWrapper extends EntryPoint { + @Memo() + public entry(): void { + A._instantiateImpl(undefined, (() => { + return new A(); + }), undefined, undefined, undefined); + } + public constructor() {} +} + +@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_A { +} +`; + +const expectedUIHeaderScript: string = ` +import { Memo as Memo } from \"arkui.incremental.annotation\"; +import { ComponentBuilder as ComponentBuilder } from \"arkui.component.builder\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; + +function main() {} + +@Memo() +export function FakeComponentA(style: (@Memo() ((instance: FakeComponentAAttribute)=> void) | undefined), str: string, @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponentB(style: (@Memo() ((instance: FakeComponentBAttribute)=> void) | undefined), options?: FakeOptions, @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponentC(style: (@Memo() ((instance: FakeComponentCAttribute)=> void) | undefined), @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponentAImpl(style: (@Memo() ((instance: FakeComponentAAttribute)=> void) | undefined), content?: @Memo() (()=> void)): void + +@Memo() +export function FakeComponentBImpl(style: (@Memo() ((instance: FakeComponentBAttribute)=> void) | undefined), content?: @Memo() (()=> void)): void + +@Memo() +export function FakeComponentCImpl(style: (@Memo() ((instance: FakeComponentCAttribute)=> void) | undefined), content?: @Memo() (()=> void)): void + +interface FakeOptions { + get str(): (string | undefined) { + return undefined; + } + set str(str: (string | undefined)) { + throw new InvalidStoreAccessError(); + } +} + +interface FakeComponentAAttribute { + setFakeComponentAOptions(str: string): this +} + +interface FakeComponentBAttribute { + setFakeComponentBOptions(options?: FakeOptions): this +} + +interface FakeComponentCAttribute { + setFakeComponentCOptions(): this +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.declContexts?.[utilExternalSourceName]?.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIHeaderScript)); + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIScript)); +} + +pluginTester.run( + 'test multiple different @ComponentBuilder', + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + tracing: { externalSourceNames: [utilExternalSourceName] }, + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/overload-component-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/overload-component-builder.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c119893ef464af31c1dfa3a3c8c5cd34cab92b7f --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/overload-component-builder.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; +const INNER_COMPONENT_DIR_PATH: string = 'inner-component'; +const UTIL_DIR_PATH: string = 'utils'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve( + getRootPath(), + MOCK_ENTRY_DIR_PATH, + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + 'overload-component-builder.ets' + ), +]; + +const utilExternalSourceName = [ + buildConfig.packageName, + MOCK_ENTRY_DIR_PATH.replaceAll('/', '.'), + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + UTIL_DIR_PATH, + 'fake-overload-component' +].join('.'); + +const pluginTester = new PluginTester('test multiple overload @ComponentBuilder', buildConfig); + +const parsedTransform: Plugins = { + name: 'overload-component-builder', + parsed: uiTransform().parsed, +}; + +const expectedUIScript: string = ` +import { Memo as Memo } from \"arkui.incremental.annotation\"; +import { FakeComponentAttribute as FakeComponentAttribute } from \"${utilExternalSourceName}\"; +import { FakeComponentImpl as FakeComponentImpl } from \"${utilExternalSourceName}\"; +import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; +import { PageLifeCycle as PageLifeCycle } from \"arkui.component.customComponent\"; +import { EntryPoint as EntryPoint } from \"arkui.component.customComponent\"; +import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; +import { Entry as Entry, Component as Component } from \"arkui.component.customComponent\"; +import { FakeComponent as FakeComponent } from \"./utils/fake-overload-component\"; + +function main() {} + +__EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ + bundleName: \"com.example.mock\", + moduleName: \"entry\", + pagePath: \"../../../builder-lambda/inner-component/overload-component-builder\", + pageFullPath: \"test/demo/mock/builder-lambda/inner-component/overload-component-builder\", + integratedHsp: \"false\", +} as NavInterface)); + +@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct A extends CustomComponent implements PageLifeCycle { + public __initializeStruct(initializers: (__Options_A | undefined), @Memo() content: ((()=> void) | undefined)): void {} + public __updateStruct(initializers: (__Options_A | undefined)): void {} + @Memo() + public build() { + FakeComponentImpl(@Memo() ((instance: FakeComponentAttribute): void => { + instance.setFakeComponentOptions(\"fake-component\"); + return; + }), undefined); + FakeComponentImpl(@Memo() ((instance: FakeComponentAttribute): void => { + instance.setFakeComponentOptions({}); + return; + }), undefined); + FakeComponentImpl(@Memo() ((instance: FakeComponentAttribute): void => { + instance.setFakeComponentOptions(undefined); + return; + }), @Memo() (() => {})); + } + public constructor() {} + + static { + + } +} + +class __EntryWrapper extends EntryPoint { + @Memo() + public entry(): void { + A._instantiateImpl(undefined, (() => { + return new A(); + }), undefined, undefined, undefined); + } + public constructor() {} +} + +@Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_A { +} +`; + +const expectedUIHeaderScript: string = ` +import { Memo as Memo } from "arkui.incremental.annotation"; +import { ComponentBuilder as ComponentBuilder } from "arkui.component.builder"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; + +function main() {} + +@Memo() +export function FakeComponent(style: (@Memo() ((instance: FakeComponentAttribute)=> void) | undefined), str: string, @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponent(style: (@Memo() ((instance: FakeComponentAttribute)=> void) | undefined), options?: FakeOptions, @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponent(style: (@Memo() ((instance: FakeComponentAttribute)=> void) | undefined), @Memo() content_?: (()=> void)): void + +@Memo() +export function FakeComponentImpl(style: (@Memo() ((instance: FakeComponentAttribute)=> void) | undefined), content?: @Memo() (()=> void)): void + +interface FakeOptions { + get str(): (string | undefined) { + return undefined; + } + set str(str: (string | undefined)) { + throw new InvalidStoreAccessError(); + } + +} + +interface FakeComponentAttribute { + setFakeComponentOptions(options?: FakeOptions): this + setFakeComponentOptions(): this + setFakeComponentOptions(str: string): this + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.declContexts?.[utilExternalSourceName]?.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIHeaderScript)); + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIScript)); +} + +pluginTester.run( + 'test multiple overload @ComponentBuilder', + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + tracing: { externalSourceNames: [utilExternalSourceName] }, + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/simple-component.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/simple-component.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..49cb18b7ef2e1f8516abb446f6f8d0089fd1bb0a --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/inner-component/simple-component.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; +const INNER_COMPONENT_DIR_PATH: string = 'inner-component'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve( + getRootPath(), + MOCK_ENTRY_DIR_PATH, + BUILDER_LAMBDA_DIR_PATH, + INNER_COMPONENT_DIR_PATH, + 'simple-component.ets' + ), +]; +const pluginTester = new PluginTester('test builder-lambda simple component', buildConfig); + +function testBuilderLambdaTransformer(this: PluginTestContext): void { + const expectedScript: string = ` +import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; +import { Memo as Memo } from "arkui.incremental.annotation"; +import { ColumnImpl as ColumnImpl } from "arkui.component.column"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; +import { Column as Column, ColumnAttribute as ColumnAttribute } from \"arkui.component.column\"; +function main() {} +class MyStateSample { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { + instance.setColumnOptions(undefined).applyAttributesFinish(); + return; + }), @Memo() (() => {})); + } + public constructor() {} +} +`; + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +function testMemoTransformer(this: PluginTestContext): void { + const expectedScript: string = ` +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"arkui.incremental.runtime.state\"; +import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; +import { Memo as Memo } from "arkui.incremental.annotation"; +import { ColumnImpl as ColumnImpl } from "arkui.component.column"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; +import { Column as Column, ColumnAttribute as ColumnAttribute } from \"arkui.component.column\"; +function main() {} +class MyStateSample { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + const __memo_scope = __memo_context.scope(((__memo_id) + (263357132)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setColumnOptions(undefined).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + (147296800)), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + } + public constructor() {} +} +`; + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'transform simple component', + [collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testBuilderLambdaTransformer], + 'checked:memo-no-recheck': [testMemoTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts index c9f35b0ea0f5aaa79e7baa5752761c4332fa1e59..ef7034b236d57dc340f80575acd750bf05d35ed3 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/builder-lambda/style-with-receiver.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -41,7 +41,7 @@ const expectedScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -51,7 +51,7 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; -import { memo as memo } from "@ohos.arkui.stateManagement"; +import { Memo as Memo } from "@ohos.arkui.stateManagement"; import { Text as Text, TextAttribute as TextAttribute, Column as Column, Component as Component } from "@ohos.arkui.component"; @@ -60,33 +60,36 @@ import hilog from "@ohos.hilog"; function main() {} -@memo() function cardStyle(this: TextAttribute, num: number, str: string): TextAttribute { +@Memo() +function cardStyle(this: TextAttribute, num: number, str: string): TextAttribute { this.fontSize(num); this.backgroundColor(str); return this; } -@memo() function style22(this: TextAttribute): TextAttribute { +@Memo() +function style22(this: TextAttribute): TextAttribute { this.fontWeight(700); return this; } @Component() final struct MM extends CustomComponent { - public __initializeStruct(initializers: (__Options_MM | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MM | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MM | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { style22(cardStyle(instance.setTextOptions("hello world", undefined).height(200).fontColor("#000000"), 600, "#eeeeee").fontSize(60).fontWeight(400)).width(900).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { cardStyle(instance.setTextOptions("hello world", undefined), 600, "#eeeeee").applyAttributesFinish(); return; }), undefined); @@ -94,7 +97,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_MM { @@ -108,7 +114,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test function with receiver style transformstion', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts index 8e2eee14ea2fa50457077e3d0ad379d14ff86ea1..19ca63d2517b459e70b65d29e83ef66151ecab4d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/declare-component.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -52,7 +52,8 @@ import { PropRef as PropRef, State as State } from "@ohos.arkui.stateManagement" @State() public code: number; - @Builder() public build(): void + @Builder() + public build(): void public constructor() {} @@ -62,13 +63,13 @@ import { PropRef as PropRef, State as State } from "@ohos.arkui.stateManagement" @Component() export declare interface __Options_SwipeRefresher { ${ignoreNewLines(` - content?: (ResourceStr | undefined); + @PropRef() content?: (ResourceStr | undefined); @PropRef() __backing_content?: (ResourceStr | undefined); __options_has_content?: boolean; - isLoading?: boolean; + @PropRef() isLoading?: boolean; @PropRef() __backing_isLoading?: boolean; __options_has_isLoading?: boolean; - code?: number; + @State() code?: number; @State() __backing_code?: number; __options_has_code?: boolean; `)} @@ -85,7 +86,7 @@ import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateM import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -102,24 +103,25 @@ function main() {} @State() public code: number; - @Builder() @memo() public build(): void + @Memo() + public build(): void public constructor() {} - + public static _buildCompatibleNode(options: __Options_SwipeRefresher): void } @Component() export declare interface __Options_SwipeRefresher { - ${dumpGetterSetter(GetSetDumper.BOTH, 'content', '((ResourceStr | undefined) | undefined)', [], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'content', '((ResourceStr | undefined) | undefined)', [dumpAnnotation('PropRef')], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_content', '(IPropRefDecoratedVariable<(ResourceStr | undefined)> | undefined)', [], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_content', '(boolean | undefined)', [], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'isLoading', '(boolean | undefined)', [], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'isLoading', '(boolean | undefined)', [dumpAnnotation('PropRef')], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_isLoading', '(IPropRefDecoratedVariable | undefined)', [], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_isLoading', '(boolean | undefined)', [], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'code', '(number | undefined)', [], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'code', '(number | undefined)', [dumpAnnotation('State')], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_code', '(IStateDecoratedVariable | undefined)', [], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_code', '(boolean | undefined)', [], [], false)} @@ -132,7 +134,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test declare component transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts index 8993fef733caee9871bc37908c1e4c048e83d288..b8fb701c0045e1dcead0f30466e125bb544f670a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/for-each.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; @@ -43,7 +43,7 @@ import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -73,7 +73,7 @@ class AB { } @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_arr = ((({let gensym___244068973 = initializers; (((gensym___244068973) == (null)) ? undefined : gensym___244068973.arr)})) ?? (["a", "b", "c"])); } @@ -99,65 +99,66 @@ class AB { } as Person)); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + }), @Memo() (() => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return this.arr; - }), @memo() ((item: string) => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), ((item: string) => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(item, undefined).applyAttributesFinish(); return; }), undefined); }), undefined); return; })); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return this.getArray(); - }), @memo() ((item: Person) => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), ((item: Person) => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(item.name, undefined).applyAttributesFinish(); return; }), undefined); }), undefined); return; })); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return new AB().bar; - }), @memo() ((item: string) => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), ((item: string) => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(item, undefined).applyAttributesFinish(); return; }), undefined); }), undefined); return; })); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return new AB().bar; - }), @memo() (() => {}), undefined); + }), (() => {}), undefined); return; })); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return this.getArray(); - }), @memo() (() => {}), undefined); + }), (() => {}), undefined); return; })); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return new Array("1", "2"); - }), @memo() (() => { - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + }), (() => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return new Array("1", "2"); - }), @memo() ((item: string) => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), ((item: string) => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(item, undefined).applyAttributesFinish(); return; }), undefined); @@ -171,7 +172,10 @@ class AB { } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -194,7 +198,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test ForEach component transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/namespace.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/namespace.test.ts index c5d6a48456855286f09403a08d7066689837a4f7..d696aa6178ea1ff331de5f41838dd938bb25d512 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/component/namespace.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/component/namespace.test.ts @@ -18,8 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; +import { ignoreNewLines } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -52,7 +53,6 @@ import { State as State } from "@ohos.arkui.stateManagement"; } public constructor() {} - } export namespace NS1 { @@ -77,11 +77,10 @@ export namespace NS1 { } public constructor() {} - + public static _buildCompatibleNode(options: __Options_Child): void { return; } - } export namespace NS2 { @@ -94,7 +93,6 @@ export namespace NS1 { } public constructor() {} - } @Component() export interface __Options_NS2_struct { @@ -106,7 +104,12 @@ export namespace NS1 { let s2 = "world" } @Component() export interface __Options_Child { - propVar?: string;@State() __backing_propVar?: string;__options_has_propVar?: boolean; + ${ignoreNewLines(` + @State() propVar?: string; + @State() __backing_propVar?: string; + __options_has_propVar?: boolean; + + `)} } } @@ -121,12 +124,11 @@ function testParsedTransformer(this: PluginTestContext): void { pluginTester.run( 'test namespace component transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testParsedTransformer], }, { - stopAfter: 'parsed', - tracing: { externalSourceNames: ['arkui.component.namespace'] } + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts index 08b99487855152b18e8fd1e92c4ca232d57b5eea..e9b50ef76c6175e9d8699a5c785605446995336d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -47,7 +47,7 @@ import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -56,50 +56,57 @@ import { Component as Component, Entry as Entry, Builder as Builder, BuilderPara function main() {} @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_customBuilderParam = ((((({let gensym___169376706 = initializers; (((gensym___169376706) == (null)) ? undefined : gensym___169376706.customBuilderParam)})) ?? (content))) ?? (this.customBuilder)); } public __updateStruct(initializers: (__Options_Child | undefined)): void {} + + @Memo() + public customBuilder() {} - private __backing_customBuilderParam?: @memo() (()=> void); + private __backing_customBuilderParam?: @Memo() (()=> void); - public get customBuilderParam(): @memo() (()=> void) { + public get customBuilderParam(): @Memo() (()=> void) { return this.__backing_customBuilderParam!; } - public set customBuilderParam(value: @memo() (()=> void)) { + public set customBuilderParam(value: @Memo() (()=> void)) { this.__backing_customBuilderParam = value; } - @memo() public customBuilder() {} - - @memo() public build() { + @Memo() + public build() { this.customBuilderParam(); } public constructor() {} + + static { + } } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} - @memo() public componentBuilder() { - TextImpl(@memo() ((instance: TextAttribute): void => { + @Memo() + public componentBuilder() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Parent builder", undefined).applyAttributesFinish(); return; }), undefined); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -109,15 +116,15 @@ function main() {} Child._instantiateImpl(undefined, (() => { return new Child(); }), { - customBuilderParam: @memo() (() => { + customBuilderParam: @Memo() (() => { this.componentBuilder(); }), __options_has_customBuilderParam: true, }, undefined, undefined); Child._instantiateImpl(undefined, (() => { return new Child(); - }), undefined, undefined, @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), undefined, undefined, @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Parent builder", undefined).applyAttributesFinish(); return; }), undefined); @@ -126,11 +133,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@Memo() (()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam', '(boolean | undefined)')} } @@ -146,31 +156,22 @@ import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text } from "@ohos.arkui.component"; function main() {} @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_customBuilderParam = ((((({let gensym___169376706 = initializers; (((gensym___169376706) == (null)) ? undefined : gensym___169376706.customBuilderParam)})) ?? (content))) ?? (this.customBuilder)); } public __updateStruct(initializers: (__Options_Child | undefined)): void {} - - private __backing_customBuilderParam?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - - public get customBuilderParam(): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { - return this.__backing_customBuilderParam!; - } - - public set customBuilderParam(value: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { - this.__backing_customBuilderParam = value; - } - - @memo() public customBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + + @Memo() + public customBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (252759234)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -181,8 +182,19 @@ function main() {} return; } } + + private __backing_customBuilderParam?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + public get customBuilderParam(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { + return this.__backing_customBuilderParam!; + } + + public set customBuilderParam(value: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + this.__backing_customBuilderParam = value; + } + + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (209256344)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -196,21 +208,25 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} - @memo() public componentBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public componentBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (219399173)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (137225318)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (137225318)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -229,13 +245,14 @@ function main() {} } } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (135515930)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (136716185)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (136716185)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -247,7 +264,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -262,7 +279,7 @@ function main() {} Child._instantiateImpl(__memo_context, ((__memo_id) + (218979098)), undefined, (() => { return new Child(); }), { - customBuilderParam: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + customBuilderParam: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -278,13 +295,13 @@ function main() {} }, undefined, undefined); Child._instantiateImpl(__memo_context, ((__memo_id) + (213687742)), undefined, (() => { return new Child(); - }), undefined, undefined, @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), undefined, undefined, @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (223657391)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (223657391)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -314,11 +331,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam', '(boolean | undefined)')} } @@ -338,7 +358,7 @@ function testMemoCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test builder param variable passing', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], 'checked:memo-no-recheck': [testMemoCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts index 3424408aa3253d8d3a3d8375d9226eb87e5f968d..8a5236aeb50e080df2fd72e2ffd82ba413d85d9e 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -40,13 +40,13 @@ const parsedTransform: Plugins = { const expectedAfterUIScript: string = ` import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; function main() {} @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_customBuilderParam = ((((({let gensym___169376706 = initializers; (((gensym___169376706) == (null)) ? undefined : gensym___169376706.customBuilderParam)})) ?? (content))) ?? (this.doNothingBuilder)); this.__backing_customBuilderParam2 = ((((({let gensym___14041256 = initializers; @@ -54,45 +54,51 @@ function main() {} } public __updateStruct(initializers: (__Options_Child | undefined)): void {} + + @Memo() + public doNothingBuilder() {} + + @Memo() + public doNothingBuilder2(@MemoSkip() str: string) {} - private __backing_customBuilderParam?: @memo() (()=> void); + private __backing_customBuilderParam?: @Memo() (()=> void); - public get customBuilderParam(): @memo() (()=> void) { + public get customBuilderParam(): @Memo() (()=> void) { return this.__backing_customBuilderParam!; } - public set customBuilderParam(value: @memo() (()=> void)) { + public set customBuilderParam(value: @Memo() (()=> void)) { this.__backing_customBuilderParam = value; } - private __backing_customBuilderParam2?: @memo() ((str: string)=> void); + private __backing_customBuilderParam2?: @Memo() ((str: string)=> void); - public get customBuilderParam2(): @memo() ((str: string)=> void) { + public get customBuilderParam2(): @Memo() ((str: string)=> void) { return this.__backing_customBuilderParam2!; } - public set customBuilderParam2(value: @memo() ((str: string)=> void)) { + public set customBuilderParam2(value: @Memo() ((str: string)=> void)) { this.__backing_customBuilderParam2 = value; } - @memo() public doNothingBuilder() {} - - @memo() public doNothingBuilder2(@MemoSkip() str: string) {} - - @memo() public build() { + @Memo() + public build() { this.customBuilderParam(); this.customBuilderParam2("hello"); } public constructor() {} + + static { + } } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@Memo() (()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '(@memo() ((str: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '(@Memo() ((str: string)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam2', '(boolean | undefined)')} } @@ -101,14 +107,14 @@ function main() {} const expectedAfterMemoScript: string = ` import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "arkui.incremental.runtime.state"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; function main() {} @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_customBuilderParam = ((((({let gensym___169376706 = initializers; (((gensym___169376706) == (null)) ? undefined : gensym___169376706.customBuilderParam)})) ?? (content))) ?? (this.doNothingBuilder)); this.__backing_customBuilderParam2 = ((((({let gensym___14041256 = initializers; @@ -116,28 +122,9 @@ function main() {} } public __updateStruct(initializers: (__Options_Child | undefined)): void {} - - private __backing_customBuilderParam?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - - public get customBuilderParam(): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { - return this.__backing_customBuilderParam!; - } - - public set customBuilderParam(value: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { - this.__backing_customBuilderParam = value; - } - - private __backing_customBuilderParam2?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void); - - public get customBuilderParam2(): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void) { - return this.__backing_customBuilderParam2!; - } - - public set customBuilderParam2(value: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void)) { - this.__backing_customBuilderParam2 = value; - } - - @memo() public doNothingBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + + @Memo() + public doNothingBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (174403279)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -149,7 +136,8 @@ function main() {} } } - @memo() public doNothingBuilder2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() str: string) { + @Memo() + public doNothingBuilder2(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() str: string) { const __memo_scope = __memo_context.scope(((__memo_id) + (76253767)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -160,8 +148,29 @@ function main() {} return; } } + + private __backing_customBuilderParam?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); + + public get customBuilderParam(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { + return this.__backing_customBuilderParam!; + } + + public set customBuilderParam(value: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + this.__backing_customBuilderParam = value; + } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + private __backing_customBuilderParam2?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void); + + public get customBuilderParam2(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void) { + return this.__backing_customBuilderParam2!; + } + + public set customBuilderParam2(value: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void)) { + this.__backing_customBuilderParam2 = value; + } + + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (179390036)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -176,14 +185,17 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam', '(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, str: string)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam2', '(boolean | undefined)')} } @@ -199,7 +211,7 @@ function testAfterMemoCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test builder param init with local builder', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], 'checked:memo-no-recheck': [testAfterMemoCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts index 1f9ad3635c436205d3d27f2a78bf2f9d2738df26..c4694f6455ebb1d449734e82d0559bf0eca9f192 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/optional-builder-param.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -45,7 +45,7 @@ import { RowAttribute as RowAttribute } from "arkui.component.row"; import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; import { RowImpl as RowImpl } from "arkui.component.row"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -53,15 +53,17 @@ import { Component as Component, Entry as Entry, Builder as Builder, BuilderPara function main() {} -@memo() function showTextBuilder() { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function showTextBuilder() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Hello World", undefined).applyAttributesFinish(); return; }), undefined); } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_customBuilderParam2 = ((((({let gensym___103851375 = initializers; (((gensym___103851375) == (null)) ? undefined : gensym___103851375.customBuilderParam2)})) ?? (content))) ?? (undefined)); this.__backing_customBuilderParam1 = ((((({let gensym___20169645 = initializers; @@ -72,39 +74,40 @@ function main() {} private __backing_customBuilderParam2?: ((()=> void) | undefined); - public get customBuilderParam2(): (@memo() (()=> void) | undefined) { + public get customBuilderParam2(): (@Memo() (()=> void) | undefined) { return this.__backing_customBuilderParam2; } - public set customBuilderParam2(value: (@memo() (()=> void) | undefined)) { + public set customBuilderParam2(value: (@Memo() (()=> void) | undefined)) { this.__backing_customBuilderParam2 = value; } - private __backing_customBuilderParam1?: @memo() (()=> void); + private __backing_customBuilderParam1?: @Memo() (()=> void); - public get customBuilderParam1(): @memo() (()=> void) { + public get customBuilderParam1(): @Memo() (()=> void) { return this.__backing_customBuilderParam1!; } - public set customBuilderParam1(value: @memo() (()=> void)) { + public set customBuilderParam1(value: @Memo() (()=> void)) { this.__backing_customBuilderParam1 = value; } - @memo() public build() { - RowImpl(@memo() ((instance: RowAttribute): void => { + @Memo() + public build() { + RowImpl(@Memo() ((instance: RowAttribute): void => { instance.setRowOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (this.customBuilderParam2) { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { (this.customBuilderParam2 as (()=> void))(); })); } })); - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (this.customBuilderParam2) { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { this.customBuilderParam2!(); })); } @@ -114,30 +117,35 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} - @memo() public componentBuilder() { - TextImpl(@memo() ((instance: TextAttribute): void => { + @Memo() + public componentBuilder() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Parent builder", undefined).applyAttributesFinish(); return; }), undefined); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { - customBuilderParam2: @memo() (() => { + customBuilderParam2: @Memo() (() => { this.componentBuilder(); }), __options_has_customBuilderParam2: true, @@ -146,14 +154,17 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '(((()=> void) | undefined) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam1', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam1', '(@Memo() (()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam1', '(boolean | undefined)')} } @@ -171,7 +182,7 @@ import { RowAttribute as RowAttribute } from "arkui.component.row"; import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; import { RowImpl as RowImpl } from "arkui.component.row"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -179,13 +190,15 @@ import { Component as Component, Entry as Entry, Builder as Builder, BuilderPara function main() {} -@memo() function showTextBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { +@Builder() +@Memo() +function showTextBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (183537441)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -205,7 +218,7 @@ function main() {} } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_customBuilderParam2 = ((((({let gensym___103851375 = initializers; (((gensym___103851375) == (null)) ? undefined : gensym___103851375.customBuilderParam2)})) ?? (content))) ?? (undefined)); this.__backing_customBuilderParam1 = ((((({let gensym___20169645 = initializers; @@ -216,31 +229,32 @@ function main() {} private __backing_customBuilderParam2?: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined); - public get customBuilderParam2(): (@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) { + public get customBuilderParam2(): (@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) { return this.__backing_customBuilderParam2; } - public set customBuilderParam2(value: (@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)) { + public set customBuilderParam2(value: (@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)) { this.__backing_customBuilderParam2 = value; } - private __backing_customBuilderParam1?: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); + private __backing_customBuilderParam1?: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); - public get customBuilderParam1(): @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { + public get customBuilderParam1(): @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) { return this.__backing_customBuilderParam1!; } - public set customBuilderParam1(value: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { + public set customBuilderParam1(value: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)) { this.__backing_customBuilderParam1 = value; } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (234402485)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + RowImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -252,20 +266,20 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (213104625)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (this.customBuilderParam2) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -283,14 +297,14 @@ function main() {} return; } })); - ConditionScope(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionScope(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } if (this.customBuilderParam2) { - ConditionBranch(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + ConditionBranch(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -321,21 +335,25 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} - @memo() public componentBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public componentBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (179117969)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -354,13 +372,14 @@ function main() {} } } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (245938697)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (78055758)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (78055758)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -372,7 +391,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (136716185)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -381,7 +400,7 @@ function main() {} Child._instantiateImpl(__memo_context, ((__memo_id) + (54078781)), undefined, (() => { return new Child(); }), { - customBuilderParam2: @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + customBuilderParam2: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (213687742)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -407,14 +426,17 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam2', '((((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam1', '(@memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'customBuilderParam1', '(@Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_customBuilderParam1', '(boolean | undefined)')} } @@ -434,7 +456,7 @@ function testMemoCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test optional builder param', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUICheckedTransformer], 'checked:memo-no-recheck': [testMemoCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts index 8c10161c86f5def7400bbc1ac1c61d14473d505f..ead244b116105f004eb1244ec17088245d8ff88e 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -45,7 +45,7 @@ import { RowAttribute as RowAttribute } from "arkui.component.row"; import { RowImpl as RowImpl } from "arkui.component.row"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -58,25 +58,34 @@ import { Component as Component, Row as Row, Builder as Builder, Text as Text } function main() {} -@memo() function showTextBuilder() { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +function showTextBuilder() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Hello World", undefined).applyAttributesFinish(); return; }), undefined); } -@memo() function overBuilder(@MemoSkip() params: Tmp) { - RowImpl(@memo() ((instance: RowAttribute): void => { +@Builder() +function overBuilder(@MemoSkip() params: Tmp) { + RowImpl(@Memo() ((instance: RowAttribute): void => { instance.setRowOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions((("UseStateVarByReference: ") + (params.paramA1)), undefined).applyAttributesFinish(); return; }), undefined); })); } +@Builder() +function globalBuilder(@MemoSkip() param: Person) { + TextImpl(@Memo() ((instance: TextAttribute): void => { + instance.setTextOptions("globalBuilder", undefined).applyAttributesFinish(); + return; + }), undefined); +} class Tmp { public paramA1: string = ""; @@ -85,27 +94,47 @@ class Tmp { } +interface Person { + get age(): (number | undefined) { + return undefined; + } + set age(age: (number | undefined)) { + throw new InvalidStoreAccessError(); + } + +} + @Component() final struct BuilderDemo extends CustomComponent { - public __initializeStruct(initializers: (__Options_BuilderDemo | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_BuilderDemo | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_BuilderDemo | undefined)): void {} - @memo() public build() { - RowImpl(@memo() ((instance: RowAttribute): void => { + @Memo() + public build() { + RowImpl(@Memo() ((instance: RowAttribute): void => { instance.setRowOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { showTextBuilder(); overBuilder(makeBuilderParameterProxy({}, new Map Any)>([["paramA1", ((): Any => { return "Hello"; })]]), ((gensym___: Tmp) => { gensym___.paramA1 = "Hello"; }))); + globalBuilder(makeBuilderParameterProxy({ + age: 18, + }, new Map Any)>([["age", ((): Any => { + return 18; + })]]), ((gensym___149025070: Person) => {}))); + globalBuilder(makeBuilderParameterProxy({}, new Map Any)>(), ((gensym___46528967: Person) => {}))); })); } public constructor() {} + + static { + } } @Component() export interface __Options_BuilderDemo { @@ -119,7 +148,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'global builder', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts index 48326a0caac09153e780790ebd69335eecc1594b..b4ca3ab43aad6141a40c9324e31c8fe20495f85d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -42,7 +42,7 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -57,36 +57,42 @@ function main() {} @Component() final struct BuilderDemo extends CustomComponent { - public __initializeStruct(initializers: (__Options_BuilderDemo | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_BuilderDemo | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_BuilderDemo | undefined)): void {} - @memo() public showTextBuilder() { - TextImpl(@memo() ((instance: TextAttribute): void => { + @Memo() + public showTextBuilder() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Hello World", undefined).fontSize(30).applyAttributesFinish(); return; }), undefined); } - @memo() public showTextValueBuilder(@MemoSkip() param: string) { - TextImpl(@memo() ((instance: TextAttribute): void => { + @Memo() + public showTextValueBuilder(@MemoSkip() param: string) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(param, undefined).fontSize(30).applyAttributesFinish(); return; }), undefined); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { this.showTextBuilder(); this.showTextValueBuilder("Hello @Builder"); })); } public constructor() {} + + static { + } } @Component() export interface __Options_BuilderDemo { @@ -100,7 +106,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'local builder', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-observedv2-class.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-observedv2-class.test.ts index 8b788be90a6b2e569ae9823697e68fb3c5679bf6..15ea245aac01d51044cc02a9ef7ac320bdcd9d8f 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-observedv2-class.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-observedv2-class.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -81,19 +81,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_firstName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"lastName"}) private __backing_lastName: string = "Li"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - private __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { - console.info("---------Computed----------"); - return ((((this.firstName) + (" "))) + (this.lastName)); - }), "fullName"); - - @Computed() public get fullName(): string { - return this.__computed_fullName!.get(); - } - public get firstName(): string { this.conditionalAddRef(this.__meta_firstName); return UIUtils.makeObserved(this.__backing_firstName); @@ -106,6 +93,10 @@ function main() {} this.executeOnSubscribingWatches("firstName"); } } + + @JSONRename({newName:"lastName"}) private __backing_lastName: string = "Li"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get lastName(): string { this.conditionalAddRef(this.__meta_lastName); @@ -119,9 +110,22 @@ function main() {} this.executeOnSubscribingWatches("lastName"); } } + + private __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + console.info("---------Computed----------"); + return ((((this.firstName) + (" "))) + (this.lastName)); + }), "fullName"); + + @Computed() + public get fullName(): string { + return this.__computed_fullName!.get(); + } public constructor() {} - + + static { + + } } `; @@ -131,7 +135,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Computed decorator in @ObservedV2 class', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-struct.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-struct.test.ts index 876a255779d541816dce18ebe6d6869d251932db..ebdc0418991fb5983d72c221ba0f5003597b7d8f 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-struct.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-in-struct.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -53,7 +53,7 @@ import { DividerAttribute as DividerAttribute } from "arkui.component.divider"; import { DividerImpl as DividerImpl } from "arkui.component.divider"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -71,7 +71,7 @@ function main() {} @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__computed_fullName.setOwner(this); this.__backing_firstName = STATE_MGMT_FACTORY.makeLocal(this, "firstName", "Li"); this.__backing_lastName = STATE_MGMT_FACTORY.makeLocal(this, "lastName", "Hua"); @@ -116,42 +116,44 @@ function main() {} return ((((((this.firstName) + (" "))) + (this.lastName))) + (this.age)); }), "fullName"); - @Computed() public get fullName(): string { + @Computed() + public get fullName(): string { return this.__computed_fullName!.get(); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(((((this.lastName) + (" "))) + (this.firstName)), undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(((((this.lastName) + (" "))) + (this.firstName)), undefined).applyAttributesFinish(); return; }), undefined); - DividerImpl(@memo() ((instance: DividerAttribute): void => { + DividerImpl(@Memo() ((instance: DividerAttribute): void => { instance.setDividerOptions().applyAttributesFinish(); return; })); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(this.fullName, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(this.fullName, undefined).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("changed lastName", undefined).onClick(((e) => { this.lastName += "a"; })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("changed age", undefined).onClick(((e) => { (this.age++); })).applyAttributesFinish(); @@ -161,15 +163,18 @@ function main() {} } public constructor() {} - + + static { + + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'firstName', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'firstName', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_firstName', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_firstName', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'lastName', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'lastName', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_lastName', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_lastName', '(boolean | undefined)')} @@ -185,7 +190,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Computed decorator in @ComponentV2 struct', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-no-return-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-no-return-type.test.ts index aff18976332c27a07bf0fd6a812ecc3d6a58e163..004690cf8254041ef985b0cb00dcc13ce95b92c1 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-no-return-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/computed-no-return-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -93,23 +93,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_firstName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"lastName"}) private __backing_lastName: string = "Li"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public age: number = 20; - - private __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { - if (((this.age) >= (20))) { - return new Array(0, 1, 2); - } - return ((((this.firstName) + (" "))) + (this.lastName)); - }), "fullName"); - - @Computed() public get fullName() { - return this.__computed_fullName!.get(); - } - public get firstName(): string { this.conditionalAddRef(this.__meta_firstName); return UIUtils.makeObserved(this.__backing_firstName); @@ -122,6 +105,10 @@ function main() {} this.executeOnSubscribingWatches("firstName"); } } + + @JSONRename({newName:"lastName"}) private __backing_lastName: string = "Li"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get lastName(): string { this.conditionalAddRef(this.__meta_lastName); @@ -135,13 +122,30 @@ function main() {} this.executeOnSubscribingWatches("lastName"); } } + + public age: number = 20; - public constructor() {} + private __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + if (((this.age) >= (20))) { + return new Array(0, 1, 2); + } + return ((((this.firstName) + (" "))) + (this.lastName)); + }), "fullName"); + + @Computed() + public get fullName() { + return this.__computed_fullName!.get(); + } + public constructor() {} + + static { + + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__computed_fullName.setOwner(this); this.__computed_num5.setOwner(this); this.__backing_firstName = STATE_MGMT_FACTORY.makeLocal(this, "firstName", "Li"); @@ -189,7 +193,8 @@ function main() {} return ((((((this.firstName) + (" "))) + (this.lastName))) + (this.age)); }), "fullName"); - @Computed() public get fullName() { + @Computed() + public get fullName() { return this.__computed_fullName!.get(); } @@ -197,22 +202,27 @@ function main() {} return 5; }), "num5"); - @Computed() public get num5() { + @Computed() + public get num5() { return this.__computed_num5!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} - + + static { + + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'firstName', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'firstName', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_firstName', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_firstName', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'lastName', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'lastName', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_lastName', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_lastName', '(boolean | undefined)')} @@ -228,7 +238,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Computed decorator with no return type', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts index ed3cf0607834be66d1cd42627557186b28684db3..ee9cd53d898a8b091cead1dd568017823c17da08 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -91,21 +91,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() public static __meta_firstName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"lastName"}) public static __backing_lastName: string = "Li"; - - @JSONStringifyIgnore() @JSONParseIgnore() public static __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { - return ((((Name.firstName) + (" "))) + (Name.lastName)); - }), "fullName"); - - @Computed() public static get fullName(): string { - return Name.__computed_fullName.get(); - } - - static { - - } public static get firstName(): string { Name.__meta_firstName.addRef(); return UIUtils.makeObserved(Name.__backing_firstName); @@ -117,6 +102,10 @@ function main() {} Name.__meta_firstName.fireChange(); } } + + @JSONRename({newName:"lastName"}) public static __backing_lastName: string = "Li"; + + @JSONStringifyIgnore() @JSONParseIgnore() public static __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public static get lastName(): string { Name.__meta_lastName.addRef(); @@ -129,13 +118,25 @@ function main() {} Name.__meta_lastName.fireChange(); } } + + public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + return ((((Name.firstName) + (" "))) + (Name.lastName)); + }), "fullName"); + + @Computed() + public static get fullName(): string { + return Name.__computed_fullName.get(); + } public constructor() {} - + + static { + + } } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} @@ -163,21 +164,23 @@ function main() {} return Parent.localVar1; }), "fullName"); - @Computed() public static get fullName(): string { + @Computed() + public static get fullName(): string { return Parent.__computed_fullName.get(); } - @memo() public build() {} - + @Memo() + public build() {} + public constructor() {} - + static { } } @ComponentV2() final struct Parent2 extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent2 | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent2 | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent2 | undefined)): void {} @@ -185,7 +188,8 @@ function main() {} return ((((Name.firstName) + (" "))) + (Name.lastName)); }), "fullName"); - @Computed() public static get fullName(): string { + @Computed() + public static get fullName(): string { return Parent2.__computed_fullName.get(); } @@ -193,14 +197,16 @@ function main() {} return Parent.localVar1; }), "fullName2"); - @Computed() public static get fullName2(): string { + @Computed() + public static get fullName2(): string { return Parent2.__computed_fullName2.get(); } - @memo() public build() {} - + @Memo() + public build() {} + public constructor() {} - + static { } @@ -231,23 +237,24 @@ function main() {} return ((((Name.firstName) + (" "))) + (Name.lastName)); }), "fullName"); - @Computed() public static get fullName(): string { + @Computed() + public static get fullName(): string { return Name2.__computed_fullName.get(); } - + + public constructor() {} + static { } - public constructor() {} - } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar1', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar2', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar2', '(boolean | undefined)')} @@ -264,7 +271,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Computed decorated static getter method', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts index eae3d2962d1eca6f19aadfd761853ef0ecd0a4ae..f13e08ed97dfd7c0ab6308261a85756d8f8eaae8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/base-custom-dialog.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -49,7 +49,7 @@ import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; import { ButtonImpl as ButtonImpl } from "arkui.component.button"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -72,10 +72,10 @@ import hilog from "@ohos.hilog"; function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { - public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___231706081 = initializers; (((gensym___231706081) == (null)) ? undefined : gensym___231706081.__options_has_aaController)})) { - this.__backing_aaController = initializers!.aaController + this.__backing_aaController = initializers!.aaController; } else { if (!(this.__backing_aaController)) { this.__backing_aaController = undefined @@ -143,16 +143,17 @@ function main() {} this.__backing_hh!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("CustomDialog One", undefined).fontSize(30).height(100).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("Close", undefined).onClick(((e: ClickEvent) => { if (((this.aaController) != (undefined))) { this.aaController!.close(); @@ -164,6 +165,10 @@ function main() {} } public constructor() {} + + static { + + } public __setDialogController__(controller: CustomDialogController): void { this.__backing_aaController = controller; @@ -171,11 +176,11 @@ function main() {} } @Component() final struct CustomDialogUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___56650533 = initializers; (((gensym___56650533) == (null)) ? undefined : gensym___56650533.dialogController)})) ?? (({let gensym___249621102: Any; gensym___249621102 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___249621102 as CustomDialogController)); @@ -237,12 +242,13 @@ function main() {} console.info("Click the callback in the blank area"); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("click me", undefined).onClick(((e: ClickEvent) => { if (((this.dialogController) != (null))) { this.dialogController!.open(); @@ -254,14 +260,17 @@ function main() {} } public constructor() {} - + + static { + + } } @CustomDialog() export interface __Options_CustomDialogExample { ${dumpGetterSetter(GetSetDumper.BOTH, 'aaController', '((CustomDialogController | undefined) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_aaController', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_text', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_text', '(boolean | undefined)')} @@ -271,7 +280,7 @@ function main() {} ${dumpGetterSetter(GetSetDumper.BOTH, 'confirm', '((()=> void) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_confirm', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'hh', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'hh', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_hh', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_hh', '(boolean | undefined)')} @@ -290,7 +299,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic capability of @CustomDialog', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts index d85f67e10f16b411f1f4a3e9add8317947fc33e7..3f72e0d984457017773962cd5b3b420cf6c78a88 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/builder-dialog-options.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -63,7 +63,6 @@ import hilog from "@ohos.hilog"; } public constructor() {} - } @Component() final struct CustomDialogUser2 extends CustomComponent { @@ -76,7 +75,6 @@ import hilog from "@ohos.hilog"; } public constructor() {} - } @Component() export interface __Options_CustomDialogUser { @@ -103,7 +101,7 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -115,16 +113,20 @@ import hilog from "@ohos.hilog"; function main() {} -@memo() function builder1(@MemoSkip() str: string) {} +@Builder() +@Memo() +function builder1(@MemoSkip() str: string) {} -@memo() function builder2() {} +@Builder() +@Memo() +function builder2() {} @Component() final struct CustomDialogUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___51459619 = initializers; (((gensym___51459619) == (null)) ? undefined : gensym___51459619.dialogController)})) ?? (({let gensym___203542966: Any; gensym___203542966 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { builder1("nihao"); }), baseComponent: this, @@ -144,19 +146,23 @@ function main() {} this.__backing_dialogController = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => {})); + }), @Memo() (() => {})); } public constructor() {} - + + static { + + } } @Component() final struct CustomDialogUser2 extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser2 | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUser2 | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___176924847 = initializers; (((gensym___176924847) == (null)) ? undefined : gensym___176924847.dialogController)})) ?? (({let gensym___46528967: Any; gensym___46528967 = new CustomDialogController({ @@ -178,15 +184,19 @@ function main() {} this.__backing_dialogController = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => {})); + }), @Memo() (() => {})); } public constructor() {} - + + static { + + } } @Component() export interface __Options_CustomDialogUser { @@ -212,7 +222,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test CustomDialogControllerOptions with @Builder parameter', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts index dc2a7aa304ce3c636f1953b267bfb99c3485785e..36fe207350f1a020a42ae0f34c517ac6816d3b3e 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-build.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -38,7 +38,7 @@ const parsedTransform: Plugins = { parsed: uiTransform().parsed, }; -const expectedScript: string = ` +const expectedUIScript: string = ` import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; import { ButtonImpl as ButtonImpl } from "arkui.component.button"; @@ -49,7 +49,7 @@ import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -72,10 +72,10 @@ import hilog from "@ohos.hilog"; function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { - public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___231706081 = initializers; (((gensym___231706081) == (null)) ? undefined : gensym___231706081.__options_has_aaController)})) { - this.__backing_aaController = initializers!.aaController + this.__backing_aaController = initializers!.aaController; } else { if (!(this.__backing_aaController)) { this.__backing_aaController = undefined @@ -119,12 +119,13 @@ function main() {} this.__backing_hh!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("CustomDialog One", undefined).applyAttributesFinish(); return; }), undefined); @@ -132,27 +133,32 @@ function main() {} } public constructor() {} - + + static { + + } + public __setDialogController__(controller: CustomDialogController): void { this.__backing_aaController = controller; } } @Component() final struct CustomDialogUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("click me", undefined).onClick(((e: ClickEvent) => { let dialogController: (CustomDialogController | undefined) = ({let gensym___90667230: Any; gensym___90667230 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___90667230 as CustomDialogController)); @@ -169,18 +175,21 @@ function main() {} } public constructor() {} - + + static { + + } } @CustomDialog() export interface __Options_CustomDialogExample { ${dumpGetterSetter(GetSetDumper.BOTH, 'aaController', '((CustomDialogController | undefined) | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_aaController', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_text', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_text', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'hh', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'hh', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_hh', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_hh', '(boolean | undefined)')} @@ -191,15 +200,272 @@ function main() {} } `; -function testCheckedTransformer(this: PluginTestContext): void { - expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +function testUICheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedUIScript)); +} + +const expectedMemoScript: string = ` +function main() {} + +@CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { + public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + if (({let gensym___ = initializers; + (((gensym___) == (null)) ? undefined : gensym___.__options_has_aaController)})) { + this.__backing_aaController = initializers!.aaController; + } else { + if (!(this.__backing_aaController)) { + this.__backing_aaController = undefined + } + } + this.__backing_text = STATE_MGMT_FACTORY.makeState(this, \"text\", ((({let gensym___ = initializers; + (((gensym___) == (null)) ? undefined : gensym___.text)})) ?? (\"text\"))); + this.__backing_hh = STATE_MGMT_FACTORY.makeState(this, \"hh\", ((({let gensym___ = initializers; + (((gensym___) == (null)) ? undefined : gensym___.hh)})) ?? (\"nihao\"))); + } + + public __updateStruct(initializers: (__Options_CustomDialogExample | undefined)): void {} + + private __backing_aaController?: (CustomDialogController | undefined); + + public get aaController(): (CustomDialogController | undefined) { + return (this.__backing_aaController as (CustomDialogController | undefined)); + } + + public set aaController(value: (CustomDialogController | undefined)) { + this.__backing_aaController = value; + } + + private __backing_text?: IStateDecoratedVariable; + + public get text(): string { + return this.__backing_text!.get(); + } + + public set text(value: string) { + this.__backing_text!.set(value); + } + + private __backing_hh?: IStateDecoratedVariable; + + public get hh(): string { + return this.__backing_hh!.get(); + } + + public set hh(value: string) { + this.__backing_hh!.set(value); + } + + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setColumnOptions(undefined).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setTextOptions(\"CustomDialog One\", undefined).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), undefined); + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + } + + public constructor() {} + + static { + + } + + public __setDialogController__(controller: CustomDialogController): void { + this.__backing_aaController = controller; + } +} +@Component() final struct CustomDialogUser extends CustomComponent { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_CustomDialogUser | undefined)): void {} + + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ColumnImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setColumnOptions(undefined).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + ButtonImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ButtonAttribute): void => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); + const __memo_parameter_instance = __memo_scope.param(0, instance); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + __memo_parameter_instance.value.setButtonOptions(\"click me\", undefined).onClick(((e: ClickEvent) => { + let dialogController: (CustomDialogController | undefined) = ({let gensym___: Any; + gensym___ = new CustomDialogController({ + builder: @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); + if (__memo_scope.unchanged) { + __memo_scope.cached; + return; + } + CustomDialogExample._instantiateImpl(__memo_context, ((__memo_id) + ()), undefined, (() => { + const instance = new CustomDialogExample(); + instance.__setDialogController__((gensym___ as CustomDialogController)); + return instance; + }), {}, undefined); + { + __memo_scope.recache(); + return; + } + }), + baseComponent: this, + }) + (gensym___ as CustomDialogController)}); + })).backgroundColor(0x317aff).applyAttributesFinish(); + { + __memo_scope.recache(); + return; + } + }), undefined); + { + __memo_scope.recache(); + return; + } + })); + { + __memo_scope.recache(); + return; + } + } + + public constructor() {} + + static { + + } +} + +@CustomDialog() export interface __Options_CustomDialogExample { + get aaController(): ((CustomDialogController | undefined) | undefined) { + return undefined; + } + set aaController(aaController: ((CustomDialogController | undefined) | undefined)) { + throw new InvalidStoreAccessError(); + } + get __options_has_aaController(): (boolean | undefined) { + return undefined; + } + set __options_has_aaController(__options_has_aaController: (boolean | undefined)) { + throw new InvalidStoreAccessError(); + } + @State() + get text(): (string | undefined) { + return undefined; + } + @State() + set text(text: (string | undefined)) { + throw new InvalidStoreAccessError(); + } + get __backing_text(): (IStateDecoratedVariable | undefined) { + return undefined; + } + set __backing_text(__backing_text: (IStateDecoratedVariable | undefined)) { + throw new InvalidStoreAccessError(); + } + get __options_has_text(): (boolean | undefined) { + return undefined; + } + set __options_has_text(__options_has_text: (boolean | undefined)) { + throw new InvalidStoreAccessError(); + } + @State() + get hh(): (string | undefined) { + return undefined; + } + @State() + set hh(hh: (string | undefined)) { + throw new InvalidStoreAccessError(); + } + get __backing_hh(): (IStateDecoratedVariable | undefined) { + return undefined; + } + set __backing_hh(__backing_hh: (IStateDecoratedVariable | undefined)) { + throw new InvalidStoreAccessError(); + } + get __options_has_hh(): (boolean | undefined) { + return undefined; + } + set __options_has_hh(__options_has_hh: (boolean | undefined)) { + throw new InvalidStoreAccessError(); + } +} +@Component() export interface __Options_CustomDialogUser { + +} +`; + +function testMemoCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedMemoScript)); } pluginTester.run( 'test CustomDialogController in build', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { - 'checked:ui-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testUICheckedTransformer], + 'checked:memo-no-recheck': [testMemoCheckedTransformer] }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-method.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-method.test.ts index b8a7c220de6c6797b3eedfd6ebbaa7a68724e3b3..12a11409189885389c9191a25dd5e964fdfe67ee 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-method.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/controller-in-method.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { BaseCustomDialog as BaseCustomDialog } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, CustomDialog as CustomDialog, CustomDialogController as CustomDialogController } from "@ohos.arkui.component"; @@ -47,10 +47,10 @@ import { Component as Component, CustomDialog as CustomDialog, CustomDialogContr function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { - public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___231706081 = initializers; (((gensym___231706081) == (null)) ? undefined : gensym___231706081.__options_has_aaController)})) { - this.__backing_aaController = initializers!.aaController + this.__backing_aaController = initializers!.aaController; } else { if (!(this.__backing_aaController)) { this.__backing_aaController = undefined @@ -70,9 +70,13 @@ function main() {} this.__backing_aaController = value; } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + static { + + } public __setDialogController__(controller: CustomDialogController): void { this.__backing_aaController = controller; @@ -80,11 +84,11 @@ function main() {} } @Component() final struct CustomDialogUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___95501822 = initializers; (((gensym___95501822) == (null)) ? undefined : gensym___95501822.dialogController)})) ?? (({let gensym___46528967: Any; gensym___46528967 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___46528967 as CustomDialogController)); @@ -111,7 +115,7 @@ function main() {} public updateController1() { this.dialogController = ({let gensym___17371929: Any; gensym___17371929 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___17371929 as CustomDialogController)); @@ -127,7 +131,7 @@ function main() {} public updateController2() { let temp = ({let gensym___90667230: Any; gensym___90667230 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___90667230 as CustomDialogController)); @@ -141,10 +145,14 @@ function main() {} this.dialogController = temp; } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} - + + static { + + } } @CustomDialog() export interface __Options_CustomDialogExample { @@ -166,7 +174,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test CutomDialogController assignment in method', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/declare-custom-dialog.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/declare-custom-dialog.test.ts index b9f4b2a6d371163245f3777418c3cc56239a1c8a..2d0e00369ef77aaffdbf421e50004a5a9ace8ef0 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/declare-custom-dialog.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/declare-custom-dialog.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { collectNoRecheck, memoNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -40,7 +40,7 @@ const parsedTransform: Plugins = { const expectedCheckedScript: string = ` import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { BaseCustomDialog as BaseCustomDialog } from "arkui.component.customComponent"; import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -56,20 +56,20 @@ function main() {} public hh: string; - @Builder() @memo() public build(): void + @Memo() + public build(): void public constructor() {} public static _buildCompatibleNode(options: __Options_CustomDialogExample): void - } @Component() final struct CustomDialogUserV1 extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUserV1 | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUserV1 | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___51459619 = initializers; (((gensym___51459619) == (null)) ? undefined : gensym___51459619.dialogController)})) ?? (({let gensym___203542966: Any; gensym___203542966 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___203542966 as CustomDialogController)); @@ -93,18 +93,22 @@ function main() {} this.__backing_dialogController = value; } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} - + + static { + + } } @ComponentV2() final struct CustomDialogUserV2 extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_CustomDialogUserV2 | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUserV2 | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___176924847 = initializers; (((gensym___176924847) == (null)) ? undefined : gensym___176924847.dialogController)})) ?? (({let gensym___46528967: Any; gensym___46528967 = new CustomDialogController({ - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___46528967 as CustomDialogController)); @@ -128,17 +132,21 @@ function main() {} this.__backing_dialogController = value; } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} - + + static { + + } } @CustomDialog() export declare interface __Options_CustomDialogExample { ${dumpGetterSetter(GetSetDumper.BOTH, 'aaController', '((CustomDialogController | undefined) | undefined)', [], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_aaController', '(boolean | undefined)', [], [], false)} - ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)', [], [], false)} + ${dumpGetterSetter(GetSetDumper.BOTH, 'text', '(string | undefined)', [dumpAnnotation('State')], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_text', '(IStateDecoratedVariable | undefined)', [], [], false)} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_text', '(boolean | undefined)', [], [], false)} @@ -166,7 +174,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test declared struct @CustomDialog transformation', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts index fc9e89a5ae087c06fe898ba83ef8ecf16fd04afb..9229c2c305c8bb368f32a963a12160b813097ad1 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/custom-dialog/extends-dialog-controller.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -45,7 +45,7 @@ import { ButtonImpl as ButtonImpl } from "arkui.component.button"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -60,10 +60,10 @@ import { CustomDialog as CustomDialog, CustomDialogController as CustomDialogCon function main() {} @CustomDialog() final struct CustomDialogExample extends BaseCustomDialog { - public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogExample | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___231706081 = initializers; (((gensym___231706081) == (null)) ? undefined : gensym___231706081.__options_has_aaController)})) { - this.__backing_aaController = initializers!.aaController + this.__backing_aaController = initializers!.aaController; } else { if (!(this.__backing_aaController)) { this.__backing_aaController = undefined @@ -83,14 +83,19 @@ function main() {} this.__backing_aaController = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => {})); + }), @Memo() (() => {})); } public constructor() {} + + static { + + } public __setDialogController__(controller: CustomDialogController): void { this.__backing_aaController = controller; @@ -118,13 +123,13 @@ class DialogControllerV3 extends DialogControllerV2 { } @Component() final struct CustomDialogUser extends CustomComponent { - public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CustomDialogUser | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_dialogController = ((({let gensym___176924847 = initializers; (((gensym___176924847) == (null)) ? undefined : gensym___176924847.dialogController)})) ?? ((({let gensym___46528967: Any; gensym___46528967 = new CustomDialogController(({ gridCount: 4, showInSubWindow: true, - builder: @memo() (() => { + builder: @Memo() (() => { CustomDialogExample._instantiateImpl(undefined, (() => { const instance = new CustomDialogExample(); instance.__setDialogController__((gensym___46528967 as CustomDialogController)); @@ -148,12 +153,13 @@ class DialogControllerV3 extends DialogControllerV2 { this.__backing_dialogController = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("click me", undefined).onClick(((e: ClickEvent) => { if (((this.dialogController) != (null))) { this.dialogController!.open(); @@ -165,6 +171,10 @@ class DialogControllerV3 extends DialogControllerV2 { } public constructor() {} + + static { + + } } @@ -187,7 +197,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test extends class of CutomDialogController', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/decorator-no-type.test.deprecated.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/decorator-no-type.test.deprecated.ts index 9f312228b92eb260962bf10ce666427039f7c0c4..dc8749ac828932f9d0d1a859573aa397044f8302 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/decorator-no-type.test.deprecated.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/decorator-no-type.test.deprecated.ts @@ -49,7 +49,7 @@ import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateM import { IParamOnceDecoratedVariable as IParamOnceDecoratedVariable } from "arkui.stateManagement.decorator"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -126,7 +126,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -135,7 +135,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -256,7 +256,7 @@ final class StateType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_stateVar1 = STATE_MGMT_FACTORY.makeState(this, "stateVar1", (((({let gensym___213853607 = initializers; (((gensym___213853607) == (null)) ? undefined : gensym___213853607.stateVar1)})) ?? (new Per(6))) as Per)); this.__backing_stateVar2 = STATE_MGMT_FACTORY.makePropRef>(this, "stateVar2", (((({let gensym___113574154 = initializers; @@ -362,14 +362,18 @@ final class StateType extends BaseEnum { this.__backing_stateVar11115!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() final struct V2Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_V2Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_V2Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_stateVar4 = STATE_MGMT_FACTORY.makeParamOnce>(this, "stateVar4", (((({let gensym___73118717 = initializers; (((gensym___73118717) == (null)) ? undefined : gensym___73118717.stateVar4)})) ?? (new Set(new Array("aa", "bb")))) as Set)); this.__backing_stateVar5 = STATE_MGMT_FACTORY.makeLocal>(this, "stateVar5", [true, false]); @@ -513,14 +517,18 @@ final class StateType extends BaseEnum { this.__backing_stateVar11112!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @CustomDialog() final struct CC extends BaseCustomDialog { - public __initializeStruct(initializers: (__Options_CC | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CC | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_stateVar4 = STATE_MGMT_FACTORY.makeParamOnce>(this, "stateVar4", (((({let gensym___177598336 = initializers; (((gensym___177598336) == (null)) ? undefined : gensym___177598336.stateVar4)})) ?? (new Set(new Array("aa", "bb")))) as Set)); this.__backing_stateVar5 = STATE_MGMT_FACTORY.makeLocal>(this, "stateVar5", [true, false]); @@ -664,22 +672,26 @@ final class StateType extends BaseEnum { this.__backing_stateVar11112!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(Any | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(Any | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar2', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(Any | undefined)', [dumpAnnotation('Provide', { alias: "stateVar3", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar3', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar3', '(boolean | undefined)')} @@ -689,113 +701,113 @@ final class StateType extends BaseEnum { ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Any | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11113', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11113', '(Any | undefined)', [dumpAnnotation('Provide', { alias: "me0", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11113', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11113', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11114', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11114', '(Any | undefined)', [dumpAnnotation('Provide', { alias: "stateVar11114", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11114', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11114', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11115', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11115', '(Any | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11115', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11115', '(boolean | undefined)')} } @ComponentV2() export interface __Options_V2Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Any | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar4', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Any | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar5', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Any | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar6', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar6', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar7', '(Any | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(Any | undefined)', [dumpAnnotation('Event')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Any | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar9', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Any | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar10', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '(Any | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '(Any | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar12', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar12', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11111', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11111', '(Any | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11111', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11111', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11188', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11188', '(Any | undefined)', [dumpAnnotation('Provider', { value: "var" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11188', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11188', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11112', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11112', '(Any | undefined)', [dumpAnnotation('Consumer', { value: "nihao" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11112', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11112', '(boolean | undefined)')} } @CustomDialog() export interface __Options_CC { - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Any | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar4', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Any | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar5', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Any | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar6', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar6', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar7', '(Any | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(Any | undefined)', [dumpAnnotation('Event')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Any | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar9', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Any | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar10', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '(Any | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '(Any | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar12', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar12', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11111', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11111', '(Any | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11111', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11111', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11188', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11188', '(Any | undefined)', [dumpAnnotation('Provider', { value: "var" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11188', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11188', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11112', '(Any | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11112', '(Any | undefined)', [dumpAnnotation('Consumer', { value: "nihao" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11112', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11112', '(boolean | undefined)')} diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/event/event-initialize.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/event/event-initialize.test.ts index 3bd484665c4bef4f12587bddacbb835416cfd21f..a16cc4228dc8f2afb9e27338ba22ac9b766bbb68 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/event/event-initialize.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/event/event-initialize.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -66,7 +66,7 @@ import { Event as Event, Param as Param, Local as Local } from "@ohos.arkui.stat } public constructor() {} - + } @ComponentV2() final struct Index extends CustomComponentV2 { @@ -85,19 +85,19 @@ import { Event as Event, Param as Param, Local as Local } from "@ohos.arkui.stat } public constructor() {} - + } @ComponentV2() export interface __Options_Child { ${ignoreNewLines(` - index?: number; + @Param() index?: number; @Param() __backing_index?: number; __options_has_index?: boolean; - changeIndex?: ((val: number)=> void); + @Event() changeIndex?: ((val: number)=> void); __options_has_changeIndex?: boolean; - testEvent?: ((val: number)=> number); + @Event() testEvent?: ((val: number)=> number); __options_has_testEvent?: boolean; - testEvent2?: ((val: number)=> number); + @Event() testEvent2?: ((val: number)=> number); __options_has_testEvent2?: boolean; `)} @@ -105,7 +105,7 @@ import { Event as Event, Param as Param, Local as Local } from "@ohos.arkui.stat @ComponentV2() export interface __Options_Index { ${ignoreNewLines(` - index?: number; + @Local() index?: number; @Local() __backing_index?: number; __options_has_index?: boolean; `)} @@ -122,7 +122,7 @@ import { IParamDecoratedVariable as IParamDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -139,7 +139,7 @@ import { Event as Event, Param as Param, Local as Local } from "@ohos.arkui.stat function main() {} @ComponentV2() final struct Child extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_index = STATE_MGMT_FACTORY.makeParam(this, "index", ((({let gensym___23942905 = initializers; (((gensym___23942905) == (null)) ? undefined : gensym___23942905.index)})) ?? (0))); this.__backing_changeIndex = ((({let gensym___204042774 = initializers; @@ -195,12 +195,13 @@ function main() {} this.__backing_testEvent2 = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Child index: \${this.index}\`, undefined).onClick(((e) => { this.changeIndex(20); console.log(\`after changeIndex \${this.index}\`); @@ -211,11 +212,14 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_index = STATE_MGMT_FACTORY.makeLocal(this, "index", 0); } @@ -231,11 +235,12 @@ function main() {} this.__backing_index!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -251,27 +256,30 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'index', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'index', '(number | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_index', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_index', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'changeIndex', '(((val: number)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'changeIndex', '(((val: number)=> void) | undefined)', [dumpAnnotation('Event')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_changeIndex', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'testEvent', '(((val: number)=> number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'testEvent', '(((val: number)=> number) | undefined)', [dumpAnnotation('Event')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_testEvent', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'testEvent2', '(((val: number)=> number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'testEvent2', '(((val: number)=> number) | undefined)', [dumpAnnotation('Event')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_testEvent2', '(boolean | undefined)')} } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'index', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'index', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_index', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_index', '(boolean | undefined)')} @@ -288,7 +296,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Event decorator transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts index 17937033b02d03718b6e5235c8623a190258848a..50b04f29d0cf6e61dfd735c1b2743e7163829ec8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -56,7 +56,7 @@ import { Link as Link } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct LinkParent extends CustomComponent { - public __initializeStruct(initializers: (__Options_LinkParent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_LinkParent | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___184416899 = initializers; (((gensym___184416899) == (null)) ? undefined : gensym___184416899.__options_has_linkVar1)})) { this.__backing_linkVar1 = STATE_MGMT_FACTORY.makeLink(this, "linkVar1", initializers!.__backing_linkVar1!); @@ -131,32 +131,34 @@ function main() {} this.__backing_linkVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_LinkParent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar1', '(string | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar1', '(string | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar1', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar2', '(number | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar2', '(number | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar2', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar3', '(boolean | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar3', '(boolean | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar3', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar4', '(undefined | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar4', '(undefined | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar4', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar5', '(null | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar5', '(null | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar5', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar5', '(boolean | undefined)')} @@ -169,9 +171,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Link decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts index 80f9967c219e5cc1e534d5c36d0eeb3fc6a2067c..28a816405c7f33e9fa86afb7fee07cf166e0bc42 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { GetSetDumper, dumpGetterSetter, dumpAnnotation } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -93,7 +93,7 @@ final class LinkType extends BaseEnum { } public static getValueOf(name: String): LinkType { - for (let i = 0;((i) < (LinkType.#NamesArray.length));(++i)) { + for (let i = ((LinkType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (LinkType.#NamesArray[i]))) { return LinkType.#ItemsArray[i]; } @@ -102,7 +102,7 @@ final class LinkType extends BaseEnum { } public static fromValue(value: int): LinkType { - for (let i = 0;((i) < (LinkType.#ValuesArray.length));(++i)) { + for (let i = ((LinkType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (LinkType.#ValuesArray[i]))) { return LinkType.#ItemsArray[i]; } @@ -133,7 +133,7 @@ final class LinkType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___184416899 = initializers; (((gensym___184416899) == (null)) ? undefined : gensym___184416899.__options_has_linkVar1)})) { this.__backing_linkVar1 = STATE_MGMT_FACTORY.makeLink(this, "linkVar1", initializers!.__backing_linkVar1!); @@ -306,60 +306,62 @@ final class LinkType extends BaseEnum { this.__backing_linkVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar1', '(Per | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar1', '(Per | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar1', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar2', '(Array | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar2', '(Array | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar2', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar3', '(LinkType | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar3', '(LinkType | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar3', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar4', '(Set | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar4', '(Set | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar4', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar5', '(Array | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar5', '(Array | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar5', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar6', '(Array | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar6', '(Array | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar6', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar7', '(Array | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar7', '(Array | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar7', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar8', '(LinkSourceType<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar9', '(Date | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar9', '(Date | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar9', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar10', '(Map | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar10', '(Map | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar10', '(LinkSourceType> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar11', '((string | number) | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar11', '((string | number) | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar11', '(LinkSourceType<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar12', '((Set | Per) | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkVar12', '((Set | Per) | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkVar12', '(LinkSourceType<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkVar12', '(boolean | undefined)')} @@ -372,9 +374,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Link decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-propref-state.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-propref-state.test.ts index 65ebda6c3c7d0df6401b30c202bca0973a6449a2..2d035b8d36c1f328ca2b4446f8424f34827acc13 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-propref-state.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-propref-state.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { GetSetDumper, dumpGetterSetter, dumpAnnotation } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -51,7 +51,7 @@ import { ILinkDecoratedVariable as ILinkDecoratedVariable } from "arkui.stateMan import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextInputAttribute as TextInputAttribute } from "arkui.component.textInput"; @@ -69,7 +69,7 @@ function main() {} @Component() final struct Parant extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parant | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parant | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___194626867 = initializers; (((gensym___194626867) == (null)) ? undefined : gensym___194626867.__options_has_text1)})) { this.__backing_text1 = STATE_MGMT_FACTORY.makeLink(this, "text1", initializers!.__backing_text1!); @@ -88,12 +88,13 @@ function main() {} this.__backing_text1!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextInputImpl(@memo() ((instance: TextInputAttribute): void => { + }), @Memo() (() => { + TextInputImpl(@Memo() ((instance: TextInputAttribute): void => { instance.setTextInputOptions({ text: this.text1, }).applyAttributesFinish(); @@ -115,11 +116,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___55490166 = initializers; (((gensym___55490166) == (null)) ? undefined : gensym___55490166.__options_has_childText)})) { this.__backing_childText = STATE_MGMT_FACTORY.makeLink(this, "childText", initializers!.__backing_childText!); @@ -182,8 +186,9 @@ function main() {} this.__backing_childText4!.set(value); } - @memo() public build() { - TextInputImpl(@memo() ((instance: TextInputAttribute): void => { + @Memo() + public build() { + TextInputImpl(@Memo() ((instance: TextInputAttribute): void => { instance.setTextInputOptions({ text: this.childText, }).applyAttributesFinish(); @@ -192,32 +197,33 @@ function main() {} } public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - @Component() export interface __Options_Parant { - ${dumpGetterSetter(GetSetDumper.BOTH, 'text1', '(string | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'text1', '(string | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_text1', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_text1', '(boolean | undefined)')} } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'childText', '(string | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'childText', '(string | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_childText', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_childText', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'childText2', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'childText2', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_childText2', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_childText2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'childText3', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'childText3', '(string | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_childText3', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_childText3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'childText4', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'childText4', '(string | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_childText4', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_childText4', '(boolean | undefined)')} @@ -230,7 +236,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Link decorated variables passing to other variables', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts index 0295b9af6537f8c3f8de4a6ef3234a765a4d2b86..90e20a99d13c1d915f558b71624c9a1ad0909f12 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { GetSetDumper, dumpGetterSetter, dumpAnnotation } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -53,7 +53,7 @@ import { DatePickerAttribute as DatePickerAttribute } from "arkui.component.date import { DatePickerImpl as DatePickerImpl } from "arkui.component.datePicker"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -84,7 +84,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Component() final struct DateComponent extends CustomComponent { - public __initializeStruct(initializers: (__Options_DateComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_DateComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { if (({let gensym___27735436 = initializers; (((gensym___27735436) == (null)) ? undefined : gensym___27735436.__options_has_selectedDate)})) { this.__backing_selectedDate = STATE_MGMT_FACTORY.makeLink(this, "selectedDate", initializers!.__backing_selectedDate!); @@ -103,24 +103,25 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_selectedDate!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("child increase the year by 1", undefined).onClick(((e: ClickEvent) => { this.selectedDate.setFullYear(((this.selectedDate.getFullYear()) + (1))); })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("child update the new date", undefined).margin(10).onClick(((e: ClickEvent) => { this.selectedDate = new Date("2023-09-09"); })).applyAttributesFinish(); return; }), undefined); - DatePickerImpl(@memo() ((instance: DatePickerAttribute): void => { + DatePickerImpl(@Memo() ((instance: DatePickerAttribute): void => { instance.setDatePickerOptions({ start: new Date("1970-1-1"), end: new Date("2100-1-1"), @@ -132,11 +133,14 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct ParentComponent extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_ParentComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_ParentComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_parentSelectedDate = STATE_MGMT_FACTORY.makeState(this, "parentSelectedDate", ((({let gensym___80922148 = initializers; (((gensym___80922148) == (null)) ? undefined : gensym___80922148.parentSelectedDate)})) ?? (new Date("2021-08-08")))); } @@ -153,24 +157,25 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_parentSelectedDate!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("parent increase the month by 1", undefined).margin(10).onClick(((e: ClickEvent) => { this.parentSelectedDate.setMonth(((this.parentSelectedDate.getMonth()) + (1))); })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("parent update the new date", undefined).margin(10).onClick(((e: ClickEvent) => { this.parentSelectedDate = new Date("2023-07-07"); })).applyAttributesFinish(); return; }), undefined); - DatePickerImpl(@memo() ((instance: DatePickerAttribute): void => { + DatePickerImpl(@Memo() ((instance: DatePickerAttribute): void => { instance.setDatePickerOptions({ start: new Date("1970-1-1"), end: new Date("2100-1-1"), @@ -188,13 +193,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { ParentComponent._instantiateImpl(undefined, (() => { return new ParentComponent(); }), undefined, undefined, undefined); @@ -205,14 +212,14 @@ class __EntryWrapper extends EntryPoint { } @Component() export interface __Options_DateComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'selectedDate', '(Date | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'selectedDate', '(Date | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_selectedDate', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_selectedDate', '(boolean | undefined)')} } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_ParentComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'parentSelectedDate', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'parentSelectedDate', '(Date | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_parentSelectedDate', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_parentSelectedDate', '(boolean | undefined)')} @@ -225,7 +232,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Link decorated variables passing', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-basic-type.test.ts index 4bc00dc6ff94915a376c9e6a5f0c201491447e6b..fd4461dee82e0e9eb6e33a8816cc8d7ae5ac2f24 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { Local as Local } from "@ohos.arkui.stateManagement"; function main() {} @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_localVar1 = STATE_MGMT_FACTORY.makeLocal(this, "localVar1", "stateVar1"); this.__backing_localVar2 = STATE_MGMT_FACTORY.makeLocal(this, "localVar2", 50); this.__backing_localVar3 = STATE_MGMT_FACTORY.makeLocal(this, "localVar3", true); @@ -114,30 +114,34 @@ function main() {} this.__backing_localVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar1', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar2', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(boolean | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar3', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar4', '(undefined | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar4', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar5', '(null | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar5', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar5', '(boolean | undefined)')} @@ -150,9 +154,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Local decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-complex-type.test.ts index f557a7d5edf5d5356785b2943cc251e152a0e694..68c02344f5e07ba184c44ce3ccf810c9fa84af9a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/local-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class StateType extends BaseEnum { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_localVar1 = STATE_MGMT_FACTORY.makeLocal(this, "localVar1", new Per(6)); this.__backing_localVar2 = STATE_MGMT_FACTORY.makeLocal>(this, "localVar2", new Array(3, 6, 8)); this.__backing_localVar3 = STATE_MGMT_FACTORY.makeLocal(this, "localVar3", StateType.TYPE3); @@ -257,54 +257,58 @@ final class StateType extends BaseEnum { this.__backing_localVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(Per | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar1', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar2', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(StateType | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar3', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar4', '(Set | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar4', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar5', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar5', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar6', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar6', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar7', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar7', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar9', '(Date | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar9', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar10', '(Map | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar10', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar11', '((string | number) | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar11', '(ILocalDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar12', '((Set | Per) | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar12', '(ILocalDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar12', '(boolean | undefined)')} @@ -317,9 +321,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Local decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts index 4735579f8c787d300ff8654e328ca0c5ed018541..1300c5caa507820cf6af2e70fb30e7b8ed396ccd 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -59,7 +59,7 @@ class ABB { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_Parent | undefined)): void {} @@ -93,7 +93,8 @@ class ABB { Parent.__backing_localVar3.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} @@ -103,15 +104,15 @@ class ABB { } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar1', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar1', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar2', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar2', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(ABB | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localVar3', '(ABB | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localVar3', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localVar3', '(boolean | undefined)')} @@ -124,7 +125,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test static @Local decorated variables transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts index e3a70dbb69e7ebac79c80777ec0594dc58c87c0c..f263a02aaacf73f28cdd5cfad4f9ab3035d4cad9 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -40,7 +40,7 @@ const pluginTester = new PluginTester('test LocalStorageLink complex type transf const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -105,7 +105,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -114,7 +114,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -145,7 +145,7 @@ final class Status extends BaseEnum { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_arrayA = STATE_MGMT_FACTORY.makeLocalStorageLink>(this, "Prop1", "arrayA", [1, 2, 3]); this.__backing_objectA = STATE_MGMT_FACTORY.makeLocalStorageLink(this, "Prop2", "objectA", {}); this.__backing_dateA = STATE_MGMT_FACTORY.makeLocalStorageLink(this, "Prop3", "dateA", new Date("2021-08-08")); @@ -238,14 +238,19 @@ final class Status extends BaseEnum { this.__backing_enumA!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -256,35 +261,35 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayA', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayA', '(Array | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_arrayA', '(ILocalStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_arrayA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectA', '(Object | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectA', '(Object | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'dateA', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'dateA', '(Date | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_dateA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_dateA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'setA', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'setA', '(Set | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_setA', '(ILocalStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_setA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'mapA', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'mapA', '(Map | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_mapA', '(ILocalStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_mapA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'unionA', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'unionA', '((string | undefined) | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop6" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_unionA', '(ILocalStorageLinkDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_unionA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'classA', '(Person | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'classA', '(Person | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop7" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_classA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_classA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'enumA', '(Status | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'enumA', '(Status | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop8" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_enumA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_enumA', '(boolean | undefined)')} @@ -297,7 +302,7 @@ function testLocalStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test LocalStorageLink complex type transform', - [localStorageLinkTransform, uiNoRecheck, recheck], + [localStorageLinkTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testLocalStorageLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts index 890422ab5de14a0de5b31ff3324de0cbd3fee858..90735a49ea7d37a370c82f5406c38574ff9918b4 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstoragelink/localstoragelink-primitive-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const localStorageLinkTransform: Plugins = { const pluginTester = new PluginTester('test LocalStorageLink primitive type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -69,7 +69,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_numA = STATE_MGMT_FACTORY.makeLocalStorageLink(this, "Prop1", "numA", 33); this.__backing_stringA = STATE_MGMT_FACTORY.makeLocalStorageLink(this, "Prop2", "stringA", "AA"); this.__backing_booleanA = STATE_MGMT_FACTORY.makeLocalStorageLink(this, "Prop3", "booleanA", true); @@ -107,14 +107,19 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_booleanA!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -125,15 +130,15 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'numA', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'numA', '(number | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_numA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_numA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stringA', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stringA', '(string | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stringA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stringA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanA', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanA', '(boolean | undefined)', [dumpAnnotation('LocalStorageLink', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_booleanA', '(ILocalStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_booleanA', '(boolean | undefined)')} @@ -146,7 +151,7 @@ function testLocalStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test LocalStorageLink primitive type transform', - [localStorageLinkTransform, uiNoRecheck, recheck], + [localStorageLinkTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testLocalStorageLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts index 44581928cb1377daa813ecee51cddd3ef77cad20..b02c45008712acaeca117cc0efee4efaec6d5dfe 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test @LocalStoragePropRef complex type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -89,7 +89,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -98,7 +98,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -129,7 +129,7 @@ final class Status extends BaseEnum { } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_arrayB = STATE_MGMT_FACTORY.makeLocalStoragePropRef>(this, "Prop1", "arrayB", [1, 2, 3]); this.__backing_objectB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop2", "objectB", {}); this.__backing_dateB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop3", "dateB", new Date("2021-09-09")); @@ -211,38 +211,42 @@ final class Status extends BaseEnum { this.__backing_enumB!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayB', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayB', '(Array | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_arrayB', '(ILocalStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_arrayB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectB', '(Object | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectB', '(Object | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'dateB', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'dateB', '(Date | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_dateB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_dateB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'setB', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'setB', '(Set | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_setB', '(ILocalStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_setB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'mapB', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'mapB', '(Map | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_mapB', '(ILocalStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_mapB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'classB', '(Person | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'classB', '(Person | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop7" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_classB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_classB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'enumB', '(Status | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'enumB', '(Status | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop8" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_enumB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_enumB', '(boolean | undefined)')} @@ -255,7 +259,7 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test @LocalStoragePropRef complex type transform', - [storagePropTransform, uiNoRecheck, recheck], + [storagePropTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStoragePropTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts index 030fbd8d6e373618506f82078753c7b184368fa6..0fce9aaa9f8292af71b0b8ef84ed1a3991055dcd 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/localstorageprop-ref/localstorageprop-ref-primitive-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test @LocalStoragePropRef primitive type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { LocalStoragePropRef as LocalStoragePropRef } from "@ohos.arkui.stateMan function main() {} @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_numB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop1", "numB", 43); this.__backing_stringB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop2", "stringB", "BB"); this.__backing_booleanB = STATE_MGMT_FACTORY.makeLocalStoragePropRef(this, "Prop3", "booleanB", false); @@ -114,30 +114,34 @@ function main() {} this.__backing_nullB!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'numB', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'numB', '(number | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_numB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_numB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stringB', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stringB', '(string | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stringB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stringB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanB', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanB', '(boolean | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_booleanB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_booleanB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'undefinedB', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'undefinedB', '(undefined | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_undefinedB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_undefinedB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'nullB', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'nullB', '(null | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_nullB', '(ILocalStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_nullB', '(boolean | undefined)')} @@ -150,7 +154,7 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test @LocalStoragePropRef primitive type transform', - [storagePropTransform, uiNoRecheck, recheck], + [storagePropTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStoragePropTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/enum-monitor-params.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/enum-monitor-params.test.ts index c3500c0bdf35d9a84fcf9e0913a248bf5a8d6d61..bbffb61533ecb03d1ba6243d233be5ba6bfedbb8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/enum-monitor-params.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/enum-monitor-params.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -109,7 +109,7 @@ final class MonitorNames extends BaseEnum { } public static getValueOf(name: String): MonitorNames { - for (let i = 0;((i) < (MonitorNames.#NamesArray.length));(++i)) { + for (let i = ((MonitorNames.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (MonitorNames.#NamesArray[i]))) { return MonitorNames.#ItemsArray[i]; } @@ -118,7 +118,7 @@ final class MonitorNames extends BaseEnum { } public static fromValue(value: String): MonitorNames { - for (let i = 0;((i) < (MonitorNames.#StringValuesArray.length));(++i)) { + for (let i = ((MonitorNames.#StringValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (MonitorNames.#StringValuesArray[i]))) { return MonitorNames.#ItemsArray[i]; } @@ -172,15 +172,7 @@ final class MonitorNames extends BaseEnum { @JSONRename({newName:"name"}) private __backing_name: string = "Tom"; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_name: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"strArr"}) private __backing_strArr: Array = ["North", "east"]; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_strArr: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - private __monitor_changeCCC: (IMonitorDecoratedVariable | undefined); - - @Monitor({value:[MonitorNames.name1, MonitorNames.name2, MonitorNames.name3]}) public changeCCC(monitor: IMonitor) {} - + public get name(): string { this.conditionalAddRef(this.__meta_name); return UIUtils.makeObserved(this.__backing_name); @@ -193,6 +185,10 @@ final class MonitorNames extends BaseEnum { this.executeOnSubscribingWatches("name"); } } + + @JSONRename({newName:"strArr"}) private __backing_strArr: Array = ["North", "east"]; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_strArr: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get strArr(): Array { this.conditionalAddRef(this.__meta_strArr); @@ -206,6 +202,11 @@ final class MonitorNames extends BaseEnum { this.executeOnSubscribingWatches("strArr"); } } + + private __monitor_changeCCC: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:[MonitorNames.name1, MonitorNames.name2, MonitorNames.name3]}) + public changeCCC(monitor: IMonitor) {} public constructor() { this.__monitor_changeCCC = STATE_MGMT_FACTORY.makeMonitor([{ @@ -229,11 +230,14 @@ final class MonitorNames extends BaseEnum { this.changeCCC(_m); })); } + + static { + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_varF = STATE_MGMT_FACTORY.makeLocal(this, "varF", new FFF()); this.__monitor_changeEEE = STATE_MGMT_FACTORY.makeMonitor([{ path: "varF.ff", @@ -260,16 +264,21 @@ final class MonitorNames extends BaseEnum { private __monitor_changeEEE: (IMonitorDecoratedVariable | undefined); - @Monitor({value:[MonitorNames.name4]}) public changeEEE(monitor: IMonitor) {} + @Monitor({value:[MonitorNames.name4]}) + public changeEEE(monitor: IMonitor) {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'varF', '(FFF | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'varF', '(FFF | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_varF', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_varF', '(boolean | undefined)')} @@ -282,7 +291,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Monitor decorator enum parameters transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-before-state-variable.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-before-state-variable.test.ts index 765ae5caa1c3a07558b7e949c5e33a997e0bbdf1..6238dac39d46cec8b90be303c0176fe0304e29e8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-before-state-variable.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-before-state-variable.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -56,7 +56,7 @@ import { Monitor as Monitor, Local as Local, IMonitor as IMonitor } from "@ohos. function main() {} @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeLocal(this, "message", "Hello World"); this.__backing_name = STATE_MGMT_FACTORY.makeLocal(this, "name", "Tom"); this.__backing_age = STATE_MGMT_FACTORY.makeLocal(this, "age", 24); @@ -84,13 +84,40 @@ function main() {} } public __updateStruct(initializers: (__Options_Index | undefined)): void {} - + private __monitor_onStrChange1: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["message", "name"]}) + public onStrChange1(monitor: IMonitor) { + monitor.dirty.forEach(((path: string) => { + console.info(\`\${path} changed from \${({let gensym%%_74 = monitor.value(path); + (((gensym%%_74) == (null)) ? undefined : gensym%%_74.before)})} to \${({let gensym%%_75 = monitor.value(path); + (((gensym%%_75) == (null)) ? undefined : gensym%%_75.now)})}\`); + })); + } private __monitor_onStrChange2: (IMonitorDecoratedVariable | undefined); + @Monitor({value:["message", "name"]}) + public onStrChange2(monitor: IMonitor) { + monitor.dirty.forEach(((path: string) => { + console.info(\`\${path} changed from \${({let gensym%%_76 = monitor.value(path); + (((gensym%%_76) == (null)) ? undefined : gensym%%_76.before)})} to \${({let gensym%%_77 = monitor.value(path); + (((gensym%%_77) == (null)) ? undefined : gensym%%_77.now)})}\`); + })); + } + private __monitor_onStrChange3: (IMonitorDecoratedVariable | undefined); + @Monitor({value:["name"]}) + public onStrChange3(monitor: IMonitor) { + monitor.dirty.forEach(((path: string) => { + console.info(\`\${path} changed from \${({let gensym%%_78 = monitor.value(path); + (((gensym%%_78) == (null)) ? undefined : gensym%%_78.before)})} to \${({let gensym%%_79 = monitor.value(path); + (((gensym%%_79) == (null)) ? undefined : gensym%%_79.now)})}\`); + })); + } + private __backing_message?: ILocalDecoratedVariable; public get message(): string { @@ -121,46 +148,26 @@ function main() {} this.__backing_age!.set(value); } - @Monitor({value:["message", "name"]}) public onStrChange1(monitor: IMonitor) { - monitor.dirty.forEach(((path: string) => { - console.info(\`\${path} changed from \${({let gensym%%_74 = monitor.value(path); - (((gensym%%_74) == (null)) ? undefined : gensym%%_74.before)})} to \${({let gensym%%_75 = monitor.value(path); - (((gensym%%_75) == (null)) ? undefined : gensym%%_75.now)})}\`); - })); - } - - @Monitor({value:["message", "name"]}) public onStrChange2(monitor: IMonitor) { - monitor.dirty.forEach(((path: string) => { - console.info(\`\${path} changed from \${({let gensym%%_76 = monitor.value(path); - (((gensym%%_76) == (null)) ? undefined : gensym%%_76.before)})} to \${({let gensym%%_77 = monitor.value(path); - (((gensym%%_77) == (null)) ? undefined : gensym%%_77.now)})}\`); - })); - } - - @Monitor({value:["name"]}) public onStrChange3(monitor: IMonitor) { - monitor.dirty.forEach(((path: string) => { - console.info(\`\${path} changed from \${({let gensym%%_78 = monitor.value(path); - (((gensym%%_78) == (null)) ? undefined : gensym%%_78.before)})} to \${({let gensym%%_79 = monitor.value(path); - (((gensym%%_79) == (null)) ? undefined : gensym%%_79.now)})}\`); - })); - } - - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'name', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'name', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_name', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_name', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'age', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'age', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_age', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_age', '(boolean | undefined)')} @@ -173,7 +180,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Monitor method declared before state variables', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-observedv2-class.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-observedv2-class.test.ts index 9fb86407286e4493b3b30d3005294f783551fa67..4944c3cff0b3d6ea15e4a2940c3106359659b231 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-observedv2-class.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-observedv2-class.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -41,7 +41,7 @@ const parsedTransform: Plugins = { const expectedScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -100,42 +100,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_name: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"region"}) private __backing_region: string = "North"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_region: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"job"}) private __backing_job: string = "Teacher"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_job: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public age: number = 25; - - private __monitor_onNameChange: (IMonitorDecoratedVariable | undefined); - - private __monitor_onAgeChange: (IMonitorDecoratedVariable | undefined); - - private __monitor_onChange: (IMonitorDecoratedVariable | undefined); - - @Monitor({value:["name"]}) public onNameChange(monitor: IMonitor) { - console.info(\`name change from \${({let gensym%%_43 = monitor.value(); - (((gensym%%_43) == (null)) ? undefined : gensym%%_43.before)})} to \${({let gensym%%_44 = monitor.value(); - (((gensym%%_44) == (null)) ? undefined : gensym%%_44.now)})}\`); - } - - @Monitor({value:["age"]}) public onAgeChange(monitor: IMonitor) { - console.info(\`age change from \${({let gensym%%_45 = monitor.value(); - (((gensym%%_45) == (null)) ? undefined : gensym%%_45.before)})} to \${({let gensym%%_46 = monitor.value(); - (((gensym%%_46) == (null)) ? undefined : gensym%%_46.now)})}\`); - } - - @Monitor({value:["region", "job"]}) public onChange(monitor: IMonitor) { - monitor.dirty.forEach(((path: string) => { - console.info(\`\${path} change from \${({let gensym%%_47 = monitor.value(path); - (((gensym%%_47) == (null)) ? undefined : gensym%%_47.before)})} to \${({let gensym%%_48 = monitor.value(path); - (((gensym%%_48) == (null)) ? undefined : gensym%%_48.now)})}\`); - })); - } - public get name(): string { this.conditionalAddRef(this.__meta_name); return UIUtils.makeObserved(this.__backing_name); @@ -148,6 +112,10 @@ function main() {} this.executeOnSubscribingWatches("name"); } } + + @JSONRename({newName:"region"}) private __backing_region: string = "North"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_region: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get region(): string { this.conditionalAddRef(this.__meta_region); @@ -161,6 +129,10 @@ function main() {} this.executeOnSubscribingWatches("region"); } } + + @JSONRename({newName:"job"}) private __backing_job: string = "Teacher"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_job: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get job(): string { this.conditionalAddRef(this.__meta_job); @@ -174,6 +146,37 @@ function main() {} this.executeOnSubscribingWatches("job"); } } + + public age: number = 25; + + private __monitor_onNameChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["name"]}) + public onNameChange(monitor: IMonitor) { + console.info(\`name change from \${({let gensym%%_43 = monitor.value(); + (((gensym%%_43) == (null)) ? undefined : gensym%%_43.before)})} to \${({let gensym%%_44 = monitor.value(); + (((gensym%%_44) == (null)) ? undefined : gensym%%_44.now)})}\`); + } + + private __monitor_onAgeChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["age"]}) + public onAgeChange(monitor: IMonitor) { + console.info(\`age change from \${({let gensym%%_45 = monitor.value(); + (((gensym%%_45) == (null)) ? undefined : gensym%%_45.before)})} to \${({let gensym%%_46 = monitor.value(); + (((gensym%%_46) == (null)) ? undefined : gensym%%_46.now)})}\`); + } + + private __monitor_onChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["region", "job"]}) + public onChange(monitor: IMonitor) { + monitor.dirty.forEach(((path: string) => { + console.info(\`\${path} change from \${({let gensym%%_47 = monitor.value(path); + (((gensym%%_47) == (null)) ? undefined : gensym%%_47.before)})} to \${({let gensym%%_48 = monitor.value(path); + (((gensym%%_48) == (null)) ? undefined : gensym%%_48.now)})}\`); + })); + } public constructor() { this.__monitor_onNameChange = STATE_MGMT_FACTORY.makeMonitor([{ @@ -206,11 +209,14 @@ function main() {} this.onChange(_m); })); } + + static { + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_info = ((({let gensym___130514200 = initializers; (((gensym___130514200) == (null)) ? undefined : gensym___130514200.info)})) ?? (new Info())); } @@ -227,30 +233,31 @@ function main() {} this.__backing_info = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change name", undefined).onClick(((e) => { this.info.name = "Jack"; })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change age", undefined).onClick(((e) => { this.info.age = 26; })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change region", undefined).onClick(((e) => { this.info.region = "South"; })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change job", undefined).onClick(((e) => { this.info.job = "Driver"; })).applyAttributesFinish(); @@ -260,7 +267,10 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { @@ -276,7 +286,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Monitor decorator in @ObservedV2 class transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-struct.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-struct.test.ts index fa61af136e639a3fbbeece2034679152a6f3d8cf..cd90eb160e7781fd1f785698da6526d9603bab5d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-struct.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-in-struct.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -47,7 +47,7 @@ import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -66,7 +66,7 @@ function main() {} @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeLocal(this, "message", "Hello World"); this.__backing_name = STATE_MGMT_FACTORY.makeLocal(this, "name", "Tom"); this.__backing_age = STATE_MGMT_FACTORY.makeLocal(this, "age", 24); @@ -119,7 +119,8 @@ function main() {} private __monitor_onStrChange: (IMonitorDecoratedVariable | undefined); - @Monitor({value:["message", "name"]}) public onStrChange(monitor: IMonitor) { + @Monitor({value:["message", "name"]}) + public onStrChange(monitor: IMonitor) { monitor.dirty.forEach(((path: string) => { console.info(\`\${path} changed from \${({let gensym%%_43 = monitor.value(path); (((gensym%%_43) == (null)) ? undefined : gensym%%_43.before)})} to \${({let gensym%%_44 = monitor.value(path); @@ -127,12 +128,13 @@ function main() {} })); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change string", undefined).onClick(((e) => { this.message += "!"; this.name = "Jack"; @@ -143,19 +145,22 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'name', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'name', '(string | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_name', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_name', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'age', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'age', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_age', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_age', '(boolean | undefined)')} @@ -168,7 +173,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Monitor decorator in struct transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-params.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-params.test.ts index 06610b51beaf01c327ab7d2a28baf2c725579fe5..37321f2c4b9046c43d1ba2611af41ee4116c9d8d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-params.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/monitor/monitor-params.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -146,28 +146,6 @@ class GGG { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_name: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"strArr"}) private __backing_strArr: Array = ["North", "east"]; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_strArr: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"job"}) private __backing_job: AAA = new AAA(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_job: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public age: number = 25; - - private __monitor_onNameChange: (IMonitorDecoratedVariable | undefined); - - private __monitor_onAgeChange: (IMonitorDecoratedVariable | undefined); - - private __monitor_onJobChange: (IMonitorDecoratedVariable | undefined); - - @Monitor({value:["name"]}) public onNameChange(monitor: IMonitor) {} - - @Monitor({value:["strArr.0", "age"]}) public onAgeChange(monitor: IMonitor) {} - - @Monitor({value:["job.aaa.bbb.ccc.1.dd.0"]}) public onJobChange(monitor: IMonitor) {} - public get name(): string { this.conditionalAddRef(this.__meta_name); return UIUtils.makeObserved(this.__backing_name); @@ -180,6 +158,10 @@ class GGG { this.executeOnSubscribingWatches("name"); } } + + @JSONRename({newName:"strArr"}) private __backing_strArr: Array = ["North", "east"]; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_strArr: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get strArr(): Array { this.conditionalAddRef(this.__meta_strArr); @@ -193,6 +175,10 @@ class GGG { this.executeOnSubscribingWatches("strArr"); } } + + @JSONRename({newName:"job"}) private __backing_job: AAA = new AAA(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_job: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get job(): AAA { this.conditionalAddRef(this.__meta_job); @@ -206,6 +192,23 @@ class GGG { this.executeOnSubscribingWatches("job"); } } + + public age: number = 25; + + private __monitor_onNameChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["name"]}) + public onNameChange(monitor: IMonitor) {} + + private __monitor_onAgeChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["strArr.0", "age"]}) + public onAgeChange(monitor: IMonitor) {} + + private __monitor_onJobChange: (IMonitorDecoratedVariable | undefined); + + @Monitor({value:["job.aaa.bbb.ccc.1.dd.0"]}) + public onJobChange(monitor: IMonitor) {} public constructor() { this.__monitor_onNameChange = STATE_MGMT_FACTORY.makeMonitor([{ @@ -245,11 +248,14 @@ class GGG { this.onJobChange(_m); })); } + + static { + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_per = STATE_MGMT_FACTORY.makeLocal(this, "per", new EEE()); this.__backing_v1 = STATE_MGMT_FACTORY.makeLocal(this, "v1", true); this.__backing_numArr = STATE_MGMT_FACTORY.makeLocal>(this, "numArr", ["1", "3", "5"]); @@ -310,24 +316,29 @@ class GGG { private __monitor_onPerChange: (IMonitorDecoratedVariable | undefined); - @Monitor({value:["per.ee.ff", "v1", "numArr.1"]}) public onPerChange(monitor: IMonitor) {} + @Monitor({value:["per.ee.ff", "v1", "numArr.1"]}) + public onPerChange(monitor: IMonitor) {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'per', '(EEE | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'per', '(EEE | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_per', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_per', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'v1', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'v1', '(boolean | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_v1', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_v1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'numArr', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'numArr', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_numArr', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_numArr', '(boolean | undefined)')} @@ -340,7 +351,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Monitor decorator parameters transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts index 4e4ba398f1766b5d15d479cf612bbae52ed5bc7c..7c4817f777e4d814d6dc1b8deab7f83d95350288 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-basic.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const objectlinkTrackTransform: Plugins = { const pluginTester = new PluginTester('test objectlink basic transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObjectLinkDecoratedVariable as IObjectLinkDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -95,7 +95,10 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public constructor() {} + + static { + } } @Observed() class B implements IObservedObject, ISubscribedWatches { @@ -128,11 +131,14 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public constructor() {} + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_objectlinkvar = STATE_MGMT_FACTORY.makeObjectLink(this, "objectlinkvar", (({let gensym___248819442 = initializers; (((gensym___248819442) == (null)) ? undefined : gensym___248819442.objectlinkvar)}) as A)); } @@ -150,14 +156,18 @@ function main() {} return this.__backing_objectlinkvar!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() final struct MyStateSample2 extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample2 | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample2 | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_objectlinkvar1 = STATE_MGMT_FACTORY.makeObjectLink<(A | undefined)>(this, "objectlinkvar1", (({let gensym___219806589 = initializers; (((gensym___219806589) == (null)) ? undefined : gensym___219806589.objectlinkvar1)}) as (A | undefined))); this.__backing_objectlinkvar2 = STATE_MGMT_FACTORY.makeObjectLink<(A | B)>(this, "objectlinkvar2", (({let gensym___217261862 = initializers; @@ -199,29 +209,33 @@ function main() {} return this.__backing_objectlinkvar3!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar', '(A | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar', '(A | undefined)', [dumpAnnotation('ObjectLink')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar', '(IObjectLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectlinkvar', '(boolean | undefined)')} } @Component() export interface __Options_MyStateSample2 { - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar1', '((A | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar1', '((A | undefined) | undefined)', [dumpAnnotation('ObjectLink')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar1', '(IObjectLinkDecoratedVariable<(A | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectlinkvar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar2', '((A | B) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar2', '((A | B) | undefined)', [dumpAnnotation('ObjectLink')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar2', '(IObjectLinkDecoratedVariable<(A | B)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectlinkvar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar3', '((A | B | null) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar3', '((A | B | null) | undefined)', [dumpAnnotation('ObjectLink')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar3', '(IObjectLinkDecoratedVariable<(A | B | null)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectlinkvar3', '(boolean | undefined)')} @@ -234,7 +248,7 @@ function testObjectLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test objectlink basic transform', - [objectlinkTrackTransform, uiNoRecheck, recheck], + [objectlinkTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObjectLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts index fb24b5871efd085773871b2f2df5342a754023e1..711185521102746a3ffe7582c78898bf9922f5bc 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/objectlink/objectlink-observed.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -46,7 +46,7 @@ import { IObjectLinkDecoratedVariable as IObjectLinkDecoratedVariable } from "ar import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -126,7 +126,10 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ public getDate(): number { return 0; } + + static { + } } @Observed() class NewDate implements IObservedObject, ISubscribedWatches { @@ -160,10 +163,6 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ @JSONRename({newName:"data"}) private __backing_data: DateClass = new DateClass(11); - public constructor(data: DateClass) { - this.data = data; - } - public get data(): DateClass { this.conditionalAddRef(this.__meta); return this.__backing_data; @@ -176,11 +175,18 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.executeOnSubscribingWatches("data"); } } + + public constructor(data: DateClass) { + this.data = data; + } + + static { + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_label = ((({let gensym___171896504 = initializers; (((gensym___171896504) == (null)) ? undefined : gensym___171896504.label)})) ?? ("date")); this.__backing_data = STATE_MGMT_FACTORY.makeObjectLink(this, "data", (({let gensym___209155591 = initializers; @@ -210,12 +216,13 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ return this.__backing_data!.get(); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("child increase the day by 1", undefined).onClick(((e: ClickEvent) => { this.data.setDate(((this.data.getDate()) + (1))); })).applyAttributesFinish(); @@ -225,11 +232,14 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Parent extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_newData = STATE_MGMT_FACTORY.makeState(this, "newData", ((({let gensym___225289068 = initializers; (((gensym___225289068) == (null)) ? undefined : gensym___225289068.newData)})) ?? (new NewDate(new DateClass("2023-1-1"))))); } @@ -246,11 +256,12 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_newData!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -259,13 +270,13 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ data: this.newData.data, __options_has_data: true, }, undefined, undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("parent update the new date", undefined).onClick(((e: ClickEvent) => { this.newData.data = new DateClass("2023-07-07"); })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("ViewB: this.newData = new NewDate(new DateClass('2023-08-20'))", undefined).onClick(((e: ClickEvent) => { this.newData = new NewDate(new DateClass("2023-08-20")); })).applyAttributesFinish(); @@ -275,11 +286,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { Parent._instantiateImpl(undefined, (() => { return new Parent(); }), undefined, undefined, undefined); @@ -293,14 +308,14 @@ class __EntryWrapper extends EntryPoint { ${dumpGetterSetter(GetSetDumper.BOTH, 'label', '(string | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_label', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'data', '(DateClass | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'data', '(DateClass | undefined)', [dumpAnnotation('ObjectLink')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_data', '(IObjectLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_data', '(boolean | undefined)')} } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'newData', '(NewDate | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'newData', '(NewDate | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_newData', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_newData', '(boolean | undefined)')} @@ -313,7 +328,7 @@ function testObjectLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test objectlink observed transform', - [objectlinkTrackTransform, uiNoRecheck, recheck], + [objectlinkTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObjectLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts index cc05926d56b5900e64836deb94f085ef2fbd1e0f..10184b23fbb7fa622af738fee02a1862ab68b58b 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonrename.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed class transform with JsonRe const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -99,27 +99,7 @@ function main() {} @JSONRename({newName:"var2"}) private __backing_var2: number = 2; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var2: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name3"}) public var3: number = 3; - - @TestDecor() public var4: number = 4; - - @JSONRename({value:"name5"}) private __backing_var5: number = 5; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name6"}) @TestDecor() public var6: number = 6; - - @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name8"}) @TestDecor() private __backing_var8: number = 8; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public constructor() {} - + public get var2(): number { this.conditionalAddRef(this.__meta_var2); return this.__backing_var2; @@ -132,7 +112,15 @@ function main() {} this.executeOnSubscribingWatches("var2"); } } + + @JSONRename({value:"name3"}) public var3: number = 3; + + @TestDecor() public var4: number = 4; + @JSONRename({value:"name5"}) private __backing_var5: number = 5; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var5(): number { this.conditionalAddRef(this.__meta_var5); return this.__backing_var5; @@ -145,6 +133,12 @@ function main() {} this.executeOnSubscribingWatches("var5"); } } + + @JSONRename({value:"name6"}) @TestDecor() public var6: number = 6; + + @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get var7(): number { this.conditionalAddRef(this.__meta_var7); @@ -158,7 +152,11 @@ function main() {} this.executeOnSubscribingWatches("var7"); } } + + @JSONRename({value:"name8"}) @TestDecor() private __backing_var8: number = 8; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var8(): number { this.conditionalAddRef(this.__meta_var8); return this.__backing_var8; @@ -171,18 +169,27 @@ function main() {} this.executeOnSubscribingWatches("var8"); } } + + public constructor() {} + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -196,7 +203,7 @@ function testObservedJsonRenameTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed only transform', - [observedJsonRenameTransform, uiNoRecheck, recheck], + [observedJsonRenameTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedJsonRenameTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts index fe2fc5a64b2834a21e05524ed85845deca6afbdb..69b7043806c42c5d5867f46a959ca746ce3e5f91 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-jsonstringifyignore.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed class transform with JsonSt const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -100,26 +100,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var2: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONStringifyIgnore() public var3: number = 3; - - @TestDecor() public var4: number = 4; - - @JSONStringifyIgnore() private __backing_var5: number = 5; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONStringifyIgnore() @TestDecor() public var6: number = 6; - - @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONStringifyIgnore() @TestDecor() private __backing_var8: number = 8; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public constructor() {} - public get var2(): number { this.conditionalAddRef(this.__meta_var2); return this.__backing_var2; @@ -132,6 +112,14 @@ function main() {} this.executeOnSubscribingWatches("var2"); } } + + @JSONStringifyIgnore() public var3: number = 3; + + @TestDecor() public var4: number = 4; + + @JSONStringifyIgnore() private __backing_var5: number = 5; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get var5(): number { this.conditionalAddRef(this.__meta_var5); @@ -145,6 +133,12 @@ function main() {} this.executeOnSubscribingWatches("var5"); } } + + @JSONStringifyIgnore() @TestDecor() public var6: number = 6; + + @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get var7(): number { this.conditionalAddRef(this.__meta_var7); @@ -158,6 +152,10 @@ function main() {} this.executeOnSubscribingWatches("var7"); } } + + @JSONStringifyIgnore() @TestDecor() private __backing_var8: number = 8; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get var8(): number { this.conditionalAddRef(this.__meta_var8); @@ -171,18 +169,27 @@ function main() {} this.executeOnSubscribingWatches("var8"); } } + + public constructor() {} + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -196,7 +203,7 @@ function testObservedJsonStringifyIgnoreTransformer(this: PluginTestContext): vo pluginTester.run( 'test observed only transform', - [observedJsonStringifyIgnoreTransform, uiNoRecheck, recheck], + [observedJsonStringifyIgnoreTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedJsonStringifyIgnoreTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts index bcb2ec1b4255f31b9932a6a5f5e8ed9e6228447a..e63136a87ff481e4051bb6cf2463afc12d051806 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed only transform', buildConfi const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -95,11 +95,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); @JSONRename({newName:"propA"}) private __backing_propA: number = 1; - - @JSONRename({newName:"trackA"}) private __backing_trackA: number = 2; - - public constructor() {} - public get propA(): number { this.conditionalAddRef(this.__meta); return this.__backing_propA; @@ -113,6 +108,8 @@ function main() {} } } + @JSONRename({newName:"trackA"}) private __backing_trackA: number = 2; + public get trackA(): number { this.conditionalAddRef(this.__meta); return this.__backing_trackA; @@ -126,17 +123,26 @@ function main() {} } } + public constructor() {} + + static { + + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -150,7 +156,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed only transform', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts index 6b39d4f8028177d1c7ab8cd53f2064b3149ae8d0..9f6d124269856bdf1c0a73dc99f18ba74bd2acd4 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed track transform with class const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -103,8 +103,6 @@ class E implements IObservedObject, ISubscribedWatches { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_trackE: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - public constructor() {} - public get trackE(): Info { this.conditionalAddRef(this.__meta_trackE); return this.__backing_trackE; @@ -117,7 +115,12 @@ class E implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("trackE"); } } + + public constructor() {} + + static { + } } @Observed() class E1 implements IObservedObject, ISubscribedWatches { @@ -151,10 +154,6 @@ class E implements IObservedObject, ISubscribedWatches { @JSONRename({newName:"propE1"}) private __backing_propE1: Info = new Info(); - @JSONRename({newName:"trackE1"}) private __backing_trackE1: Info = new Info(); - - public constructor() {} - public get propE1(): Info { this.conditionalAddRef(this.__meta); return this.__backing_propE1; @@ -167,6 +166,8 @@ class E implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("propE1"); } } + + @JSONRename({newName:"trackE1"}) private __backing_trackE1: Info = new Info(); public get trackE1(): Info { this.conditionalAddRef(this.__meta); @@ -180,18 +181,27 @@ class E implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("trackE1"); } } + + public constructor() {} + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -205,7 +215,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with class property', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts index 9a3367d407e34923f48a6daa63048cdf8226fca7..bd5eea2b8af7d0ca8d542f493e988c14a9a90ee8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -38,7 +38,7 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed track transform with complex type', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -110,7 +110,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -119,7 +119,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -179,71 +179,7 @@ final class Status extends BaseEnum { @JSONRename({newName:"numA"}) private __backing_numA: number = 33; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_numA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public numB: number = 33; - - public stringB: string = "AA"; - - public booleanB: boolean = true; - - public arrayB: Array = [1, 2, 3]; - - public objectB: Object = {}; - - public dateB: Date = new Date("2021-08-08"); - - public setB: Set = new Set(); - - public mapB: Map = new Map(); - - public unionB: (string | undefined) = ""; - - public classB: Person = new Person(); - - public enumB: Status = Status.NotFound; - - public constructor() {} - + public get numA(): number { this.conditionalAddRef(this.__meta_numA); return this.__backing_numA; @@ -256,7 +192,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("numA"); } } + + @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get stringA(): string { this.conditionalAddRef(this.__meta_stringA); return this.__backing_stringA; @@ -269,7 +209,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("stringA"); } } + + @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get booleanA(): boolean { this.conditionalAddRef(this.__meta_booleanA); return this.__backing_booleanA; @@ -282,7 +226,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("booleanA"); } } + + @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get arrayA(): Array { this.conditionalAddRef(this.__meta_arrayA); return this.__backing_arrayA; @@ -295,6 +243,10 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("arrayA"); } } + + @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get objectA(): Object { this.conditionalAddRef(this.__meta_objectA); @@ -308,6 +260,10 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("objectA"); } } + + @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get dateA(): Date { this.conditionalAddRef(this.__meta_dateA); @@ -321,7 +277,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("dateA"); } } + + @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get setA(): Set { this.conditionalAddRef(this.__meta_setA); return this.__backing_setA; @@ -334,7 +294,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("setA"); } } + + @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get mapA(): Map { this.conditionalAddRef(this.__meta_mapA); return this.__backing_mapA; @@ -347,7 +311,11 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("mapA"); } } + + @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get unionA(): (string | undefined) { this.conditionalAddRef(this.__meta_unionA); return this.__backing_unionA; @@ -360,6 +328,10 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("unionA"); } } + + @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get classA(): Person { this.conditionalAddRef(this.__meta_classA); @@ -373,6 +345,10 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("classA"); } } + + @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get enumA(): Status { this.conditionalAddRef(this.__meta_enumA); @@ -386,7 +362,34 @@ final class Status extends BaseEnum { this.executeOnSubscribingWatches("enumA"); } } + + public numB: number = 33; + + public stringB: string = "AA"; + public booleanB: boolean = true; + + public arrayB: Array = [1, 2, 3]; + + public objectB: Object = {}; + + public dateB: Date = new Date("2021-08-08"); + + public setB: Set = new Set(); + + public mapB: Map = new Map(); + + public unionB: (string | undefined) = ""; + + public classB: Person = new Person(); + + public enumB: Status = Status.NotFound; + + public constructor() {} + + static { + + } } @Observed() class mixed2 implements IObservedObject, ISubscribedWatches { @@ -419,29 +422,7 @@ final class Status extends BaseEnum { @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); @JSONRename({newName:"numA"}) private __backing_numA: number = 33; - - @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; - - @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; - - @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; - - @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; - - @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); - - @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); - - @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); - - @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; - - @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); - - @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; - - public constructor() {} - + public get numA(): number { this.conditionalAddRef(this.__meta); return this.__backing_numA; @@ -455,6 +436,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; + public get stringA(): string { this.conditionalAddRef(this.__meta); return this.__backing_stringA; @@ -468,6 +451,9 @@ final class Status extends BaseEnum { } } + + @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; + public get booleanA(): boolean { this.conditionalAddRef(this.__meta); return this.__backing_booleanA; @@ -481,6 +467,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; + public get arrayA(): Array { this.conditionalAddRef(this.__meta); return this.__backing_arrayA; @@ -494,6 +482,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; + public get objectA(): Object { this.conditionalAddRef(this.__meta); return this.__backing_objectA; @@ -507,6 +497,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); + public get dateA(): Date { this.conditionalAddRef(this.__meta); return this.__backing_dateA; @@ -520,6 +512,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); + public get setA(): Set { this.conditionalAddRef(this.__meta); return this.__backing_setA; @@ -533,6 +527,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); + public get mapA(): Map { this.conditionalAddRef(this.__meta); return this.__backing_mapA; @@ -546,6 +542,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; + public get unionA(): (string | undefined) { this.conditionalAddRef(this.__meta); return this.__backing_unionA; @@ -559,6 +557,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); + public get classA(): Person { this.conditionalAddRef(this.__meta); return this.__backing_classA; @@ -572,6 +572,8 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; + public get enumA(): Status { this.conditionalAddRef(this.__meta); return this.__backing_enumA; @@ -585,6 +587,11 @@ final class Status extends BaseEnum { } } + public constructor() {} + + static { + + } } class mixed3 implements IObservedObject, ISubscribedWatches { @@ -618,48 +625,6 @@ class mixed3 implements IObservedObject, ISubscribedWatches { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_numA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public constructor() {} - public get numA(): number { this.conditionalAddRef(this.__meta_numA); return this.__backing_numA; @@ -672,6 +637,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("numA"); } } + + @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get stringA(): string { this.conditionalAddRef(this.__meta_stringA); @@ -685,6 +654,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("stringA"); } } + + @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get booleanA(): boolean { this.conditionalAddRef(this.__meta_booleanA); @@ -698,6 +671,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("booleanA"); } } + + @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get arrayA(): Array { this.conditionalAddRef(this.__meta_arrayA); @@ -711,6 +688,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("arrayA"); } } + + @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get objectA(): Object { this.conditionalAddRef(this.__meta_objectA); @@ -724,6 +705,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("objectA"); } } + + @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get dateA(): Date { this.conditionalAddRef(this.__meta_dateA); @@ -737,6 +722,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("dateA"); } } + + @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get setA(): Set { this.conditionalAddRef(this.__meta_setA); @@ -750,6 +739,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("setA"); } } + + @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get mapA(): Map { this.conditionalAddRef(this.__meta_mapA); @@ -763,6 +756,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("mapA"); } } + + @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get unionA(): (string | undefined) { this.conditionalAddRef(this.__meta_unionA); @@ -776,6 +773,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("unionA"); } } + + @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get classA(): Person { this.conditionalAddRef(this.__meta_classA); @@ -789,6 +790,10 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("classA"); } } + + @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get enumA(): Status { this.conditionalAddRef(this.__meta_enumA); @@ -802,22 +807,32 @@ class mixed3 implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("enumA"); } } + + public constructor() {} + + static { + } } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -837,7 +852,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with complex type', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts index 2912e3bd9900bb598d9e72e329ce10f6d5dc3e7c..1f9abeb1aac7d5137606a49f3d935125a0bb97af 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed track transform with extend const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -95,11 +95,7 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); @JSONRename({newName:"propA"}) private __backing_propA: number = 1; - - @JSONRename({newName:"trackA"}) private __backing_trackA: number = 2; - - public constructor() {} - + public get propA(): number { this.conditionalAddRef(this.__meta); return this.__backing_propA; @@ -113,6 +109,8 @@ function main() {} } } + @JSONRename({newName:"trackA"}) private __backing_trackA: number = 2; + public get trackA(): number { this.conditionalAddRef(this.__meta); return this.__backing_trackA; @@ -126,6 +124,11 @@ function main() {} } } + public constructor() {} + + static { + + } } class G extends A { @@ -166,8 +169,6 @@ class G extends A { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_propG: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - public constructor() {} - public get propG(): number { this.conditionalAddRef(this.__meta_propG); return this.__backing_propG; @@ -181,17 +182,26 @@ class G extends A { } } + public constructor() {} + + static { + + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -205,7 +215,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with extends', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts index 47d3b05dc007b4ca041bb581dc079c5ef97c33b2..5e46ad9b5abab01668b44f4209eb368cf8910e3d 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -40,7 +40,7 @@ const pluginTester = new PluginTester('test observed track transform with implem const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -105,12 +105,10 @@ interface trackInterface { @JSONStringifyIgnore() @JSONParseIgnore() private __meta: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"propF"}) private __backing_propF: number = 1; - - @JSONRename({newName:"trackF"}) private __backing_trackF: number = 2; - public constructor() {} - + + @JSONRename({newName:"propF"}) private __backing_propF: number = 1; + public get propF(): number { this.conditionalAddRef(this.__meta); return this.__backing_propF; @@ -124,6 +122,8 @@ interface trackInterface { } } + @JSONRename({newName:"trackF"}) private __backing_trackF: number = 2; + public get trackF(): number { this.conditionalAddRef(this.__meta); return this.__backing_trackF; @@ -136,18 +136,25 @@ interface trackInterface { this.executeOnSubscribingWatches("trackF"); } } + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -161,7 +168,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with implements', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts index 50f9e49f87825b452d61b9bec6c34899c7d3fb12..eeb63b0adbec2e0ce4e70a4bdd20a231404ebbdd 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test observed with track transform', buil const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -96,14 +96,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_trackB: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"newProp"}) private __backing_newProp?: boolean; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_newProp: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public constructor(newProp: boolean) { - this.newProp = newProp; - } - public get trackB(): number { this.conditionalAddRef(this.__meta_trackB); return this.__backing_trackB; @@ -116,6 +108,10 @@ function main() {} this.executeOnSubscribingWatches("trackB"); } } + + @JSONRename({newName:"newProp"}) private __backing_newProp?: boolean; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_newProp: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); public get newProp(): boolean { this.conditionalAddRef(this.__meta_newProp); @@ -129,18 +125,29 @@ function main() {} this.executeOnSubscribingWatches("newProp"); } } + + public constructor(newProp: boolean) { + this.newProp = newProp; + } + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -154,7 +161,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed with track transform', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts index 2433e838fb2239b4814f2fe5b72d519bc0372e70..842b65edf3633c4d172f48349ca2014bbd149f5a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const pluginTester = new PluginTester('test track only transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; @@ -98,8 +98,6 @@ class C implements IObservedObject, ISubscribedWatches { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_trackC: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - public constructor() {} - public get trackC(): number { this.conditionalAddRef(this.__meta_trackC); return this.__backing_trackC; @@ -112,18 +110,27 @@ class C implements IObservedObject, ISubscribedWatches { this.executeOnSubscribingWatches("trackC"); } } + + public constructor() {} + + static { + } } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -137,7 +144,7 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test track only transform', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/base-observedv2-trace.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/base-observedv2-trace.test.ts index 3cbdcfbba9a0cf7b1d8b0bf646b60267e6f9497a..db39e8b2ea555022012019aef9fba3debfd9f01a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/base-observedv2-trace.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/base-observedv2-trace.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -97,7 +97,10 @@ function main() {} } public constructor() {} + + static { + } } @ObservedV2() class DD implements IObservedObject, ISubscribedWatches { @@ -127,12 +130,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() private __meta_traceE: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"tracef"}) private __backing_tracef: number = 2; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_tracef: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public vv: string; - public get traceE(): number { this.conditionalAddRef(this.__meta_traceE); return UIUtils.makeObserved(this.__backing_traceE); @@ -146,6 +143,10 @@ function main() {} } } + @JSONRename({newName:"tracef"}) private __backing_tracef: number = 2; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_tracef: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get tracef(): number { this.conditionalAddRef(this.__meta_tracef); return UIUtils.makeObserved(this.__backing_tracef); @@ -158,11 +159,16 @@ function main() {} this.executeOnSubscribingWatches("tracef"); } } - + + public vv: string; + public constructor(vv1: string) { this.vv = vv1; } + + static { + } } `; @@ -172,7 +178,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic @ObservedV2 and @Trace case', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observed-serialization.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observed-serialization.test.ts index 661e3093185cbf5cd108e79e19b5dbe54c1c7df0..5d5066086f24742262ebd66d6f2d2f33934356f0 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observed-serialization.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observed-serialization.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -84,25 +84,7 @@ function main() {} @JSONRename({newName:"var2"}) private __backing_var2: number = 2; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var2: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONStringifyIgnore() public var3: number = 3; - - @TestDecor() public var4: number = 4; - - @JSONStringifyIgnore() private __backing_var5: number = 5; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONStringifyIgnore() @TestDecor() public var6: number = 6; - - @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONStringifyIgnore() @TestDecor() private __backing_var8: number = 8; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - + public get var2(): number { this.conditionalAddRef(this.__meta_var2); return UIUtils.makeObserved(this.__backing_var2); @@ -116,6 +98,14 @@ function main() {} } } + @JSONStringifyIgnore() public var3: number = 3; + + @TestDecor() public var4: number = 4; + + @JSONStringifyIgnore() private __backing_var5: number = 5; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var5(): number { this.conditionalAddRef(this.__meta_var5); return UIUtils.makeObserved(this.__backing_var5); @@ -129,6 +119,12 @@ function main() {} } } + @JSONStringifyIgnore() @TestDecor() public var6: number = 6; + + @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var7(): number { this.conditionalAddRef(this.__meta_var7); return UIUtils.makeObserved(this.__backing_var7); @@ -142,6 +138,10 @@ function main() {} } } + @JSONStringifyIgnore() @TestDecor() private __backing_var8: number = 8; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var8(): number { this.conditionalAddRef(this.__meta_var8); return UIUtils.makeObserved(this.__backing_var8); @@ -156,7 +156,10 @@ function main() {} } public constructor() {} + + static { + } } @ObservedV2() class testJsonRename implements IObservedObject, ISubscribedWatches { @@ -185,25 +188,7 @@ function main() {} @JSONRename({newName:"var2"}) private __backing_var2: number = 2; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var2: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name3"}) public var3: number = 3; - - @TestDecor() public var4: number = 4; - - @JSONRename({value:"name5"}) private __backing_var5: number = 5; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name6"}) @TestDecor() public var6: number = 6; - - @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({value:"name8"}) @TestDecor() private __backing_var8: number = 8; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - + public get var2(): number { this.conditionalAddRef(this.__meta_var2); return UIUtils.makeObserved(this.__backing_var2); @@ -217,6 +202,14 @@ function main() {} } } + @JSONRename({value:"name3"}) public var3: number = 3; + + @TestDecor() public var4: number = 4; + + @JSONRename({value:"name5"}) private __backing_var5: number = 5; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var5: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var5(): number { this.conditionalAddRef(this.__meta_var5); return UIUtils.makeObserved(this.__backing_var5); @@ -230,6 +223,12 @@ function main() {} } } + @JSONRename({value:"name6"}) @TestDecor() public var6: number = 6; + + @TestDecor() @JSONRename({newName:"var7"}) private __backing_var7: number = 7; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var7: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var7(): number { this.conditionalAddRef(this.__meta_var7); return UIUtils.makeObserved(this.__backing_var7); @@ -243,6 +242,10 @@ function main() {} } } + @JSONRename({value:"name8"}) @TestDecor() private __backing_var8: number = 8; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_var8: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get var8(): number { this.conditionalAddRef(this.__meta_var8); return UIUtils.makeObserved(this.__backing_var8); @@ -257,7 +260,10 @@ function main() {} } public constructor() {} + + static { + } } `; @@ -267,7 +273,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @ObservedV2 class serialization', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-extends.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-extends.test.ts index 4a9e75c0bde78e340a3d03460c7c9cee1b0bd150..08de767c3b50f260b0fa6d9f09cdc2c60a0edf6c 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-extends.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-extends.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -97,7 +97,10 @@ function main() {} } public constructor() {} + + static { + } } class G extends A { @@ -146,7 +149,10 @@ class G extends A { } public constructor() {} + + static { + } } `; @@ -156,7 +162,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @ObservedV2 extends class', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-implements.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-implements.test.ts index f218a6b34ac353f9fd42e6d934162301deab177c..9131b408d5dce95d1b33069cc30e60a4cae5c224 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-implements.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-implements.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -92,11 +92,26 @@ interface trackInterface { @JSONStringifyIgnore() @JSONParseIgnore() private __meta_bb: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get bb(): boolean { + this.conditionalAddRef(this.__meta_bb); + return UIUtils.makeObserved((this.__backing_bb as boolean)); + } + + public set bb(newValue: boolean) { + if (((this.__backing_bb) !== (newValue))) { + this.__backing_bb = newValue; + this.__meta_bb.fireChange(); + this.executeOnSubscribingWatches("bb"); + } + } + + public constructor(bb: boolean) { + this.bb = bb; + } + @JSONRename({newName:"propF"}) private __backing_propF: number = 1; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_propF: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - private _$property$_trackF: number = 2; public get propF(): number { this.conditionalAddRef(this.__meta_propF); @@ -110,6 +125,8 @@ interface trackInterface { this.executeOnSubscribingWatches("propF"); } } + + private _$property$_trackF: number = 2; public get trackF(): number { return this._$property$_trackF; @@ -119,24 +136,10 @@ interface trackInterface { this._$property$_trackF = _$property$_trackF; return; } + + static { - public get bb(): boolean { - this.conditionalAddRef(this.__meta_bb); - return UIUtils.makeObserved((this.__backing_bb as boolean)); - } - - public set bb(newValue: boolean) { - if (((this.__backing_bb) !== (newValue))) { - this.__backing_bb = newValue; - this.__meta_bb.fireChange(); - this.executeOnSubscribingWatches("bb"); - } - } - - public constructor(bb: boolean) { - this.bb = bb; } - } `; @@ -146,7 +149,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @ObservedV2 implements interface', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-types.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-types.test.ts index 57c101a5d17ec2e48c46c809dfaaf7d407ed9af7..d68db06d52f3cb4a5909ceefe843cc847c0b717a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-types.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/observedv2-trace-types.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -90,7 +90,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -99,7 +99,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -153,69 +153,7 @@ final class Status extends BaseEnum { @JSONRename({newName:"numA"}) private __backing_numA: number = 33; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_numA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - public numB: number = 33; - - public stringB: string = "AA"; - - public booleanB: boolean = true; - - public arrayB: Array = [1, 2, 3]; - - public objectB: Object = {}; - - public dateB: Date = new Date("2021-08-08"); - - public setB: Set = new Set(); - - public mapB: Map = new Map(); - - public unionB: (string | undefined) = ""; - - public classB: Person = new Person(); - - public enumB: Status = Status.NotFound; - + public get numA(): number { this.conditionalAddRef(this.__meta_numA); return UIUtils.makeObserved(this.__backing_numA); @@ -229,6 +167,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"stringA"}) private __backing_stringA: string = "AA"; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_stringA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get stringA(): string { this.conditionalAddRef(this.__meta_stringA); return UIUtils.makeObserved(this.__backing_stringA); @@ -242,6 +184,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"booleanA"}) private __backing_booleanA: boolean = true; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_booleanA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get booleanA(): boolean { this.conditionalAddRef(this.__meta_booleanA); return UIUtils.makeObserved(this.__backing_booleanA); @@ -255,6 +201,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"arrayA"}) private __backing_arrayA: Array = [1, 2, 3]; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_arrayA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get arrayA(): Array { this.conditionalAddRef(this.__meta_arrayA); return UIUtils.makeObserved(this.__backing_arrayA); @@ -268,6 +218,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"objectA"}) private __backing_objectA: Object = {}; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_objectA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get objectA(): Object { this.conditionalAddRef(this.__meta_objectA); return UIUtils.makeObserved(this.__backing_objectA); @@ -281,6 +235,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"dateA"}) private __backing_dateA: Date = new Date("2021-08-08"); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_dateA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get dateA(): Date { this.conditionalAddRef(this.__meta_dateA); return UIUtils.makeObserved(this.__backing_dateA); @@ -294,6 +252,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"setA"}) private __backing_setA: Set = new Set(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_setA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get setA(): Set { this.conditionalAddRef(this.__meta_setA); return UIUtils.makeObserved(this.__backing_setA); @@ -307,6 +269,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"mapA"}) private __backing_mapA: Map = new Map(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_mapA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get mapA(): Map { this.conditionalAddRef(this.__meta_mapA); return UIUtils.makeObserved(this.__backing_mapA); @@ -320,6 +286,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"unionA"}) private __backing_unionA: (string | undefined) = ""; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_unionA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get unionA(): (string | undefined) { this.conditionalAddRef(this.__meta_unionA); return UIUtils.makeObserved(this.__backing_unionA); @@ -333,6 +303,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"classA"}) private __backing_classA: Person = new Person(); + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_classA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get classA(): Person { this.conditionalAddRef(this.__meta_classA); return UIUtils.makeObserved(this.__backing_classA); @@ -346,6 +320,10 @@ final class Status extends BaseEnum { } } + @JSONRename({newName:"enumA"}) private __backing_enumA: Status = Status.NotFound; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_enumA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get enumA(): Status { this.conditionalAddRef(this.__meta_enumA); return UIUtils.makeObserved(this.__backing_enumA); @@ -359,8 +337,33 @@ final class Status extends BaseEnum { } } + public numB: number = 33; + + public stringB: string = "AA"; + + public booleanB: boolean = true; + + public arrayB: Array = [1, 2, 3]; + + public objectB: Object = {}; + + public dateB: Date = new Date("2021-08-08"); + + public setB: Set = new Set(); + + public mapB: Map = new Map(); + + public unionB: (string | undefined) = ""; + + public classB: Person = new Person(); + + public enumB: Status = Status.NotFound; + public constructor() {} + + static { + } } `; @@ -370,7 +373,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @ObservedV2 class with different types class property', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/static-observedv2-trace.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/static-observedv2-trace.test.ts index 900acf7bcf59d7949cc6e12312032db7186340fd..6ae74564431067dc7036a4fac1ca6699e39b6196 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/static-observedv2-trace.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/static-observedv2-trace.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -87,9 +87,6 @@ function main() {} @JSONStringifyIgnore() @JSONParseIgnore() public static __meta_traceB: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - static { - - } public static get traceB(): number { CC.__meta_traceB.addRef(); return UIUtils.makeObserved(CC.__backing_traceB); @@ -104,6 +101,9 @@ function main() {} public constructor() {} + static { + + } } `; @@ -113,7 +113,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test static @Trace variable case', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/trace-with-constructor.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/trace-with-constructor.test.ts index 827fbf02656780f66f7147e5d74aca914321ee64..38379ec41cc7fd0f83e61ed86021e23b661a86ec 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/trace-with-constructor.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/observedv2-trace/trace-with-constructor.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -82,11 +82,7 @@ function main() {} @JSONRename({newName:"traceE"}) private __backing_traceE: number = 2; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_traceE: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - - @JSONRename({newName:"vv"}) private __backing_vv?: string; - - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_vv: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - + public get traceE(): number { this.conditionalAddRef(this.__meta_traceE); return UIUtils.makeObserved(this.__backing_traceE); @@ -100,6 +96,10 @@ function main() {} } } + @JSONRename({newName:"vv"}) private __backing_vv?: string; + + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_vv: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get vv(): string { this.conditionalAddRef(this.__meta_vv); return UIUtils.makeObserved((this.__backing_vv as string)); @@ -116,7 +116,10 @@ function main() {} public constructor(vv1: string) { this.vv = vv1; } + + static { + } } `; @@ -126,7 +129,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic @Trace decorated variable initialized with constuctor', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-basic-type.test.ts index b1ccd85686ba119e68c6a281d87cae6d0fec7674..cb00bd718fa656295b0aec16428f0ee5efbcebff 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-basic-type.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -39,7 +39,7 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test basic type @Once decorated variables transformation', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { Param as Param, Once as Once } from "@ohos.arkui.stateManagement"; function main() {} @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_onceVar1 = STATE_MGMT_FACTORY.makeParamOnce(this, "onceVar1", ((({let gensym___35048285 = initializers; (((gensym___35048285) == (null)) ? undefined : gensym___35048285.onceVar1)})) ?? ("stateVar1"))); this.__backing_onceVar2 = STATE_MGMT_FACTORY.makeParamOnce(this, "onceVar2", ((({let gensym___241100287 = initializers; @@ -119,30 +119,34 @@ function main() {} this.__backing_onceVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar1', '(string | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar1', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar2', '(number | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar2', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar3', '(boolean | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar3', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(undefined | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar4', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar5', '(null | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar5', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar5', '(boolean | undefined)')} @@ -155,7 +159,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Once decorated variables transformation', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-complex-type.test.ts index f2f5bccfa1872d6cdc239bbec8793e9674d35dd3..a1b69a1dcd4071561c31e5b31c6239a9c9baec22 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-complex-type.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -39,7 +39,7 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test complex type @Once decorated variables transformation', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class StateType extends BaseEnum { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_onceVar1 = STATE_MGMT_FACTORY.makeParamOnce(this, "onceVar1", ((({let gensym___126233468 = initializers; (((gensym___126233468) == (null)) ? undefined : gensym___126233468.onceVar1)})) ?? (new Per(6)))); this.__backing_onceVar2 = STATE_MGMT_FACTORY.makeParamOnce>(this, "onceVar2", ((({let gensym___261494487 = initializers; @@ -280,58 +280,62 @@ final class StateType extends BaseEnum { this.__backing_onceVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar1', '(Per | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar1', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar2', '(Array | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar2', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar3', '(StateType | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar3', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(Set | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar4', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar5', '(Array | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar5', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar6', '(Array | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar6', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar7', '(Array | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar7', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar8', '(IParamOnceDecoratedVariable<((sr: string)=> void)> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar9', '(Date | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar9', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar10', '(Map | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar10', '(IParamOnceDecoratedVariable> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar11', '((string | number) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar11', '(IParamOnceDecoratedVariable<(string | number)> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar12', '((Set | Per) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar12', '(IParamOnceDecoratedVariable<(Set | Per)> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar12', '(boolean | undefined)')} @@ -344,7 +348,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Once decorated variables transformation', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-only.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-only.test.ts index f680ddba764e5dc6df34e29a1dfa2ad681658f20..b6207327da4a41c27418673c47928aa41ccef5db 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-only.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-only.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { const pluginTester = new PluginTester('test only @Once decorated variables transformation', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IParamOnceDecoratedVariable as IParamOnceDecoratedVariable } from "arkui.stateManagement.decorator"; import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; @@ -49,7 +49,7 @@ import { Once as Once } from "@ohos.arkui.stateManagement"; function main() {} @ComponentV2() final struct Child extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_onceParamNum = STATE_MGMT_FACTORY.makeParamOnce(this, "onceParamNum", ((({let gensym___118919021 = initializers; (((gensym___118919021) == (null)) ? undefined : gensym___118919021.onceParamNum)})) ?? (0))); this.__backing_onceVar4 = STATE_MGMT_FACTORY.makeParamOnce>(this, "onceVar4", ((({let gensym___71001521 = initializers; @@ -78,18 +78,22 @@ function main() {} this.__backing_onceVar4!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamNum', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamNum', '(number | undefined)', [dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceParamNum', '(IParamOnceDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceParamNum', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceVar4', '(Set | undefined)', [dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceVar4', '(IParamOnceDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceVar4', '(boolean | undefined)')} @@ -102,7 +106,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test only @Once decorated variables transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-with-require.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-with-require.test.ts index 4f9bb49a01de2bbd3c3d729ad1065bfd3f16d0af..1c5d745e6449764e4e4e56f56c0812c3c72dc0ee 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-with-require.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/once/once-with-require.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -68,7 +68,6 @@ import { Param as Param, Once as Once, ObservedV2 as ObservedV2, Trace as Trace, } public constructor() {} - } @ComponentV2() final struct Index extends CustomComponentV2 { @@ -88,16 +87,15 @@ import { Param as Param, Once as Once, ObservedV2 as ObservedV2, Trace as Trace, } public constructor() {} - } @ComponentV2() export interface __Options_Child { ${ignoreNewLines(` - onceParamNum?: number; + @Param() @Once() onceParamNum?: number; @Param() @Once() __backing_onceParamNum?: number; __options_has_onceParamNum?: boolean; - onceParamInfo?: Info; - @Param() @Once() @Require() __backing_onceParamInfo?: Info; + @Param() @Once() @Require() onceParamInfo?: Info; + @Param() @Once() __backing_onceParamInfo?: Info; __options_has_onceParamInfo?: boolean; `)} @@ -105,10 +103,10 @@ import { Param as Param, Once as Once, ObservedV2 as ObservedV2, Trace as Trace, @ComponentV2() export interface __Options_Index { ${ignoreNewLines(` - localNum?: number; + @Local() localNum?: number; @Local() __backing_localNum?: number; __options_has_localNum?: boolean; - localInfo?: Info; + @Local() localInfo?: Info; @Local() __backing_localInfo?: Info; __options_has_localInfo?: boolean; `)} @@ -127,7 +125,7 @@ import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; import { ButtonImpl as ButtonImpl } from "arkui.component.button"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -198,11 +196,14 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() final struct Child extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_onceParamNum = STATE_MGMT_FACTORY.makeParamOnce(this, "onceParamNum", ((({let gensym___118919021 = initializers; (((gensym___118919021) == (null)) ? undefined : gensym___118919021.onceParamNum)})) ?? (0))); this.__backing_onceParamInfo = STATE_MGMT_FACTORY.makeParamOnce(this, "onceParamInfo", (initializers!.onceParamInfo as Info)); @@ -230,20 +231,21 @@ function main() {} this.__backing_onceParamInfo!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Child onceParamNum: \${this.onceParamNum}\`, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Child onceParamInfo: \${this.onceParamInfo.name}\`, undefined).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("changeOnceParamNum", undefined).onClick(((e) => { (this.onceParamNum++); })).applyAttributesFinish(); @@ -253,11 +255,14 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_localNum = STATE_MGMT_FACTORY.makeLocal(this, "localNum", 10); this.__backing_localInfo = STATE_MGMT_FACTORY.makeLocal(this, "localInfo", new Info()); } @@ -284,16 +289,17 @@ function main() {} this.__backing_localInfo!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Parent localNum: \${this.localNum}\`, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Parent localInfo: \${this.localInfo.name}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -309,26 +315,29 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamNum', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamNum', '(number | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceParamNum', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceParamNum', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamInfo', '(Info | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceParamInfo', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'onceParamInfo', '(Info | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_onceParamInfo', '(IParamOnceDecoratedVariable | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_onceParamInfo', '(boolean | undefined)')} } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'localNum', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localNum', '(number | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localNum', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localNum', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'localInfo', '(Info | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'localInfo', '(Info | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_localInfo', '(ILocalDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_localInfo', '(boolean | undefined)')} @@ -345,7 +354,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Once Decorator with @Require', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-basic-type.test.ts index 24830ae307227d67ec970983fd823307e7602fc8..26fb871a1c65171fd71879e008bc3bde530fcf1a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { Param as Param } from "@ohos.arkui.stateManagement"; function main() {} @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_paramVar1 = STATE_MGMT_FACTORY.makeParam(this, "paramVar1", ((({let gensym___264789668 = initializers; (((gensym___264789668) == (null)) ? undefined : gensym___264789668.paramVar1)})) ?? ("stateVar1"))); this.__backing_paramVar2 = STATE_MGMT_FACTORY.makeParam(this, "paramVar2", ((({let gensym___171906071 = initializers; @@ -120,30 +120,34 @@ function main() {} return this.__backing_paramVar5!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(string | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar1', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(number | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar2', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(boolean | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar3', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(undefined | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar4', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(null | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar5', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar5', '(boolean | undefined)')} @@ -156,7 +160,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Param decorated variables transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-complex-type.test.ts index dbbe30a5639b485334b0fbd4237012d83ad45229..0dc2bb6456ab93b91875feebb1be94f901fbb7ae 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class StateType extends BaseEnum { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_paramVar1 = STATE_MGMT_FACTORY.makeParam(this, "paramVar1", ((({let gensym___264789668 = initializers; (((gensym___264789668) == (null)) ? undefined : gensym___264789668.paramVar1)})) ?? (new Per(6)))); this.__backing_paramVar2 = STATE_MGMT_FACTORY.makeParam>(this, "paramVar2", ((({let gensym___171906071 = initializers; @@ -281,58 +281,62 @@ final class StateType extends BaseEnum { return this.__backing_paramVar12!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar1', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar2', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar3', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar4', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar5', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar6', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar7', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar8', '(IParamDecoratedVariable<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar9', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar10', '(IParamDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar11', '(IParamDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar12', '(IParamDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar12', '(boolean | undefined)')} @@ -345,7 +349,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Param decorated variables transformation', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts index 2c8048241e70c193b9e1420198930e66c7d962d6..085915e2b7a16543e8a27b5f90fabb6163784221 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/param/param-with-require.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -91,7 +91,7 @@ class Info { } public constructor() {} - + } @ComponentV2() final struct MiddleComponent extends CustomComponentV2 { @@ -108,7 +108,7 @@ class Info { } public constructor() {} - + } @ComponentV2() final struct SubComponent extends CustomComponentV2 { @@ -121,12 +121,12 @@ class Info { } public constructor() {} - + } @ComponentV2() export interface __Options_Index { ${ignoreNewLines(` - infoList?: Info[]; + @Local() infoList?: Info[]; @Local() __backing_infoList?: Info[]; __options_has_infoList?: boolean; `)} @@ -135,8 +135,8 @@ class Info { @ComponentV2() export interface __Options_MiddleComponent { ${ignoreNewLines(` - info?: Info; - @Require() @Param() __backing_info?: Info; + @Param() @Require() info?: Info; + @Param() __backing_info?: Info; __options_has_info?: boolean; `)} @@ -144,8 +144,8 @@ class Info { @ComponentV2() export interface __Options_SubComponent { ${ignoreNewLines(` - region?: Region; - @Require() @Param() __backing_region?: Region; + @Param() @Require() region?: Region; + @Param() __backing_region?: Region; __options_has_region?: boolean; `)} @@ -171,7 +171,7 @@ import { ButtonImpl as ButtonImpl } from "arkui.component.button"; import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; @@ -209,7 +209,7 @@ class Info { } @ComponentV2() final struct Index extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_infoList = STATE_MGMT_FACTORY.makeLocal>(this, "infoList", [new Info("Alice", 8, 0, 0), new Info("Barry", 10, 1, 20), new Info("Cindy", 18, 24, 40)]); } @@ -224,15 +224,16 @@ class Info { this.__backing_infoList!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + }), @Memo() (() => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return this.infoList; - }), @memo() ((info: Info) => { + }), ((info: Info) => { MiddleComponent._instantiateImpl(undefined, (() => { return new MiddleComponent(); }), { @@ -242,7 +243,7 @@ class Info { }), undefined); return; })); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change", undefined).onClick(((e) => { this.infoList[0] = new Info("Atom", 40, 27, 90); this.infoList[1].name = "Bob"; @@ -254,11 +255,14 @@ class Info { } public constructor() {} + + static { + } } @ComponentV2() final struct MiddleComponent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_MiddleComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MiddleComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_info = STATE_MGMT_FACTORY.makeParam(this, "info", (initializers!.info as Info)); } @@ -274,16 +278,17 @@ class Info { return this.__backing_info!.get(); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`name: \${this.info.name}\`, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`age: \${this.info.age}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -297,11 +302,14 @@ class Info { } public constructor() {} + + static { + } } @ComponentV2() final struct SubComponent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_SubComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_SubComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_region = STATE_MGMT_FACTORY.makeParam(this, "region", (initializers!.region as Region)); } @@ -317,12 +325,13 @@ class Info { return this.__backing_region!.get(); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`region: \${this.region.x}-\${this.region.y}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -330,26 +339,29 @@ class Info { } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'infoList', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'infoList', '(Array | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_infoList', '(ILocalDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_infoList', '(boolean | undefined)')} } @ComponentV2() export interface __Options_MiddleComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'info', '(Info | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_info', '(IParamDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'info', '(Info | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_info', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_info', '(boolean | undefined)')} } @ComponentV2() export interface __Options_SubComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'region', '(Region | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_region', '(IParamDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'region', '(Region | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_region', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_region', '(boolean | undefined)')} } @@ -365,7 +377,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Param Decorator with @Require', - [observedTrackTransform, uiNoRecheck, recheck], + [observedTrackTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts index fff7c8bd39c86532c6c05632418f9270a4d2869d..3f4c0a43918a8835d69aec120343494faebbd144 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -56,7 +56,7 @@ function main() {} @Component() final struct PropParent extends CustomComponent { - public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", ((({let gensym___95172135 = initializers; (((gensym___95172135) == (null)) ? undefined : gensym___95172135.propVar1)})) ?? ("propVar1"))); this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef(this, "propVar2", ((({let gensym___222490386 = initializers; @@ -142,30 +142,34 @@ function main() {} this.__backing_propVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_PropParent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(string | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar1', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '(number | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar2', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(boolean | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar3', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(undefined | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar4', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(null | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar5', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar5', '(boolean | undefined)')} @@ -178,9 +182,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @PropRef decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts index c6e94460f38a8f12c52df13726a2471c6814fc09..9bd9baa05d3d6de9160c416935ab5ba05f20e57e 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class PropType extends BaseEnum { } public static getValueOf(name: String): PropType { - for (let i = 0;((i) < (PropType.#NamesArray.length));(++i)) { + for (let i = ((PropType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (PropType.#NamesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class PropType extends BaseEnum { } public static fromValue(value: int): PropType { - for (let i = 0;((i) < (PropType.#ValuesArray.length));(++i)) { + for (let i = ((PropType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (PropType.#ValuesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class PropType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", ((({let gensym___95172135 = initializers; (((gensym___95172135) == (null)) ? undefined : gensym___95172135.propVar1)})) ?? (new Per(6)))); this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef>(this, "propVar2", ((({let gensym___222490386 = initializers; @@ -329,58 +329,62 @@ final class PropType extends BaseEnum { this.__backing_propVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(Per | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar1', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '(Array | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar2', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(PropType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(PropType | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar3', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(Set | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar4', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(Array | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar5', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar6', '(Array | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar6', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar7', '(Array | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar7', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar8', '(IPropRefDecoratedVariable<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar9', '(Date | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar9', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar10', '(Map | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar10', '(IPropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar11', '((string | number) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar11', '(IPropRefDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar12', '((Set | Per) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar12', '(IPropRefDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar12', '(boolean | undefined)')} @@ -393,9 +397,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @PropRef decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts index 5a2ddf63101f05736f221485324eb10f502b2433..9c8a6861c16cc2d21715f6e4832f813d752d17a4 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/prop-ref-without-initialization.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -68,25 +68,25 @@ import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; @Component() export interface __Options_PropParent { ${ignoreNewLines(` - propVar1?: string; + @PropRef() propVar1?: string; @PropRef() __backing_propVar1?: string; __options_has_propVar1?: boolean; - propVar2?: (number | undefined); + @PropRef() propVar2?: (number | undefined); @PropRef() __backing_propVar2?: (number | undefined); __options_has_propVar2?: boolean; - propVar3?: boolean; + @PropRef() propVar3?: boolean; @PropRef() __backing_propVar3?: boolean; __options_has_propVar3?: boolean; - propVar4?: undefined; + @PropRef() propVar4?: undefined; @PropRef() __backing_propVar4?: undefined; __options_has_propVar4?: boolean; - propVar5?: null; + @PropRef() propVar5?: null; @PropRef() __backing_propVar5?: null; __options_has_propVar5?: boolean; - propVar6?: (Array | null); + @PropRef() propVar6?: (Array | null); @PropRef() __backing_propVar6?: (Array | null); __options_has_propVar6?: boolean; - propVar7?: (Map | undefined); + @PropRef() propVar7?: (Map | undefined); @PropRef() __backing_propVar7?: (Map | undefined); __options_has_propVar7?: boolean; `)} @@ -95,7 +95,7 @@ import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; `; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -110,7 +110,7 @@ import { PropRef as PropRef } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct PropParent extends CustomComponent { - public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_propVar1 = STATE_MGMT_FACTORY.makePropRef(this, "propVar1", (initializers!.propVar1 as string)); this.__backing_propVar2 = STATE_MGMT_FACTORY.makePropRef<(number | undefined)>(this, "propVar2", (initializers!.propVar2 as (number | undefined))); this.__backing_propVar3 = STATE_MGMT_FACTORY.makePropRef(this, "propVar3", (initializers!.propVar3 as boolean)); @@ -221,38 +221,42 @@ function main() {} this.__backing_propVar7!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_PropParent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar1', '(string | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar1', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '((number | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar2', '((number | undefined) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar2', '(IPropRefDecoratedVariable<(number | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar3', '(boolean | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar3', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar4', '(undefined | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar4', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar5', '(null | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar5', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar6', '((Array | null) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar6', '((Array | null) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar6', '(IPropRefDecoratedVariable<(Array | null)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar7', '((Map | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propVar7', '((Map | undefined) | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propVar7', '(IPropRefDecoratedVariable<(Map | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propVar7', '(boolean | undefined)')} @@ -269,7 +273,7 @@ function testheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @PropRef decorated variables transformation without initialization', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:struct-no-recheck': [testheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts index ef62b3d81e951f282870e9bbed5698c5392db2e5..a8bfbcb2bc08640238274f54537cb856341f9ec7 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/prop-ref/state-to-propref.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -55,7 +55,7 @@ import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -72,7 +72,7 @@ import { PropRef as PropRef, State as State } from "@ohos.arkui.stateManagement" function main() {} @Component() final struct CountDownComponent extends CustomComponent { - public __initializeStruct(initializers: (__Options_CountDownComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_CountDownComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_count = STATE_MGMT_FACTORY.makePropRef(this, "count", ((({let gensym___58710805 = initializers; (((gensym___58710805) == (null)) ? undefined : gensym___58710805.count)})) ?? (0))); this.__backing_costOfOneAttempt = ((({let gensym___88948111 = initializers; @@ -106,29 +106,30 @@ function main() {} this.__backing_costOfOneAttempt = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ConditionScope(@memo() (() => { + }), @Memo() (() => { + ConditionScope(@Memo() (() => { if (((this.count) > (0))) { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions((((("You have") + (this.count))) + ("Nuggets left")), undefined).applyAttributesFinish(); return; }), undefined); })); } else { - ConditionBranch(@memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + ConditionBranch(@Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("Game over!", undefined).applyAttributesFinish(); return; }), undefined); })); } })); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("Try again", undefined).onClick(((e: ClickEvent) => { this.count -= this.costOfOneAttempt; })).applyAttributesFinish(); @@ -138,11 +139,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct ParentComponent extends CustomComponent { - public __initializeStruct(initializers: (__Options_ParentComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_ParentComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_countDownStartValue = STATE_MGMT_FACTORY.makeState(this, "countDownStartValue", ((({let gensym___249912438 = initializers; (((gensym___249912438) == (null)) ? undefined : gensym___249912438.countDownStartValue)})) ?? (10))); } @@ -159,22 +163,23 @@ function main() {} this.__backing_countDownStartValue!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions((((("Grant") + (this.countDownStartValue))) + ("nuggets to play.")), undefined).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("+1 - Nuggets in New Game", undefined).onClick(((e: ClickEvent) => { this.countDownStartValue += 1; })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("-1 - Nuggets in New Game", undefined).onClick(((e: ClickEvent) => { this.countDownStartValue -= 1; })).applyAttributesFinish(); @@ -192,11 +197,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_CountDownComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'count', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count', '(number | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count', '(boolean | undefined)')} @@ -206,7 +214,7 @@ function main() {} } @Component() export interface __Options_ParentComponent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'countDownStartValue', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'countDownStartValue', '(number | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_countDownStartValue', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_countDownStartValue', '(boolean | undefined)')} @@ -219,7 +227,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @PropRef decorated variables passing', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-basic-type.test.ts index acc89b07ad654ce34a53893f732f935fe7fa2fac..61e3f6d4038ae3e86ff3d1b084a3feddc7ad1922 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -64,19 +64,19 @@ import { Consume as Consume } from "@ohos.arkui.stateManagement"; @Component() export interface __Options_PropParent { ${ignoreNewLines(` - conVar1?: string; + @Consume() conVar1?: string; @Consume() __backing_conVar1?: string; __options_has_conVar1?: boolean; - conVar2?: number; + @Consume() conVar2?: number; @Consume() __backing_conVar2?: number; __options_has_conVar2?: boolean; - conVar3?: boolean; + @Consume() conVar3?: boolean; @Consume() __backing_conVar3?: boolean; __options_has_conVar3?: boolean; - conVar4?: undefined; + @Consume() conVar4?: undefined; @Consume() __backing_conVar4?: undefined; __options_has_conVar4?: boolean; - conVar5?: null; + @Consume() conVar5?: null; @Consume() __backing_conVar5?: null; __options_has_conVar5?: boolean; `)} @@ -85,7 +85,7 @@ import { Consume as Consume } from "@ohos.arkui.stateManagement"; `; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IConsumeDecoratedVariable as IConsumeDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -102,7 +102,7 @@ function main() {} @Component() final struct PropParent extends CustomComponent { - public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_conVar1 = STATE_MGMT_FACTORY.makeConsume(this, "conVar1", "conVar1"); this.__backing_conVar2 = STATE_MGMT_FACTORY.makeConsume(this, "conVar2", "conVar2"); this.__backing_conVar3 = STATE_MGMT_FACTORY.makeConsume(this, "conVar3", "conVar3"); @@ -162,30 +162,34 @@ function main() {} this.__backing_conVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_PropParent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar1', '(string | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar1', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar2', '(number | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar2', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar3', '(boolean | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar3', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar4', '(undefined | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar4', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar5', '(null | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar5', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar5', '(boolean | undefined)')} @@ -202,10 +206,10 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Consume decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-complex-type.test.ts index caa55060c206adcfe6eeb10eed72527571f9394d..a41f3868906e89d9f01b6e71536d9d366217e382 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/consume-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -95,43 +95,43 @@ enum PropType { @Component() export interface __Options_Parent { ${ignoreNewLines(` - conVar1?: Per; + @Consume() conVar1?: Per; @Consume() __backing_conVar1?: Per; __options_has_conVar1?: boolean; - conVar2?: Array; + @Consume() conVar2?: Array; @Consume() __backing_conVar2?: Array; __options_has_conVar2?: boolean; - conVar3?: PropType; + @Consume() conVar3?: PropType; @Consume() __backing_conVar3?: PropType; __options_has_conVar3?: boolean; - conVar4?: Set; + @Consume() conVar4?: Set; @Consume() __backing_conVar4?: Set; __options_has_conVar4?: boolean; - conVar5?: boolean[]; + @Consume() conVar5?: boolean[]; @Consume() __backing_conVar5?: boolean[]; __options_has_conVar5?: boolean; - conVar6?: Array; + @Consume() conVar6?: Array; @Consume() __backing_conVar6?: Array; __options_has_conVar6?: boolean; - conVar7?: Per[]; + @Consume() conVar7?: Per[]; @Consume() __backing_conVar7?: Per[]; __options_has_conVar7?: boolean; - conVar8?: ((sr: string)=> void); + @Consume() conVar8?: ((sr: string)=> void); @Consume() __backing_conVar8?: ((sr: string)=> void); __options_has_conVar8?: boolean; - conVar9?: Date; + @Consume() conVar9?: Date; @Consume() __backing_conVar9?: Date; __options_has_conVar9?: boolean; - conVar10?: Map; + @Consume() conVar10?: Map; @Consume() __backing_conVar10?: Map; __options_has_conVar10?: boolean; - conVar11?: (string | number); + @Consume() conVar11?: (string | number); @Consume() __backing_conVar11?: (string | number); __options_has_conVar11?: boolean; - conVar12?: (Set | Per); + @Consume() conVar12?: (Set | Per); @Consume() __backing_conVar12?: (Set | Per); __options_has_conVar12?: boolean; - conVar13?: (Set | null); + @Consume() conVar13?: (Set | null); @Consume() __backing_conVar13?: (Set | null); __options_has_conVar13?: boolean; `)} @@ -140,7 +140,7 @@ enum PropType { `; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IConsumeDecoratedVariable as IConsumeDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -194,7 +194,7 @@ final class PropType extends BaseEnum { } public static getValueOf(name: String): PropType { - for (let i = 0;((i) < (PropType.#NamesArray.length));(++i)) { + for (let i = ((PropType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (PropType.#NamesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -203,7 +203,7 @@ final class PropType extends BaseEnum { } public static fromValue(value: int): PropType { - for (let i = 0;((i) < (PropType.#ValuesArray.length));(++i)) { + for (let i = ((PropType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (PropType.#ValuesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -234,7 +234,7 @@ final class PropType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_conVar1 = STATE_MGMT_FACTORY.makeConsume(this, "conVar1", "conVar1"); this.__backing_conVar2 = STATE_MGMT_FACTORY.makeConsume>(this, "conVar2", "conVar2"); this.__backing_conVar3 = STATE_MGMT_FACTORY.makeConsume(this, "conVar3", "conVar3"); @@ -382,62 +382,66 @@ final class PropType extends BaseEnum { this.__backing_conVar13!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar1', '(Per | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar1', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar2', '(Array | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar2', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar3', '(PropType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar3', '(PropType | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar3', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar4', '(Set | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar4', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar5', '(Array | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar5', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar6', '(Array | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar6', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar7', '(Array | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar7', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar8', '(IConsumeDecoratedVariable<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar9', '(Date | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar9', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar10', '(Map | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar10', '(IConsumeDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar11', '((string | number) | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar11', '(IConsumeDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar12', '((Set | Per) | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar12', '(IConsumeDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar12', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar13', '((Set | null) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'conVar13', '((Set | null) | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_conVar13', '(IConsumeDecoratedVariable<(Set | null)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_conVar13', '(boolean | undefined)')} @@ -454,10 +458,10 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Consume decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts index ac5da84c8f9344bbedc3724cb1c135d3eb6b28fe..7d99b2a9b7993db2db11f237a2261d680ba7c2d2 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { Provide as Provide } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct Ancestors extends CustomComponent { - public __initializeStruct(initializers: (__Options_Ancestors | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Ancestors | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_count = STATE_MGMT_FACTORY.makeProvide<(string | undefined)>(this, "count", "count", ((({let gensym___58710805 = initializers; (((gensym___58710805) == (null)) ? undefined : gensym___58710805.count)})) ?? ("Child0")), false); this.__backing_count1 = STATE_MGMT_FACTORY.makeProvide<(string | undefined)>(this, "count1", "prov1", ((({let gensym___84874570 = initializers; @@ -155,42 +155,46 @@ function main() {} this.__backing_count7!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Ancestors { - ${dumpGetterSetter(GetSetDumper.BOTH, 'count', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "count", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count1', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count1', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "prov1", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count1', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count2', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count2', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "prov2", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count2', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count3', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count3', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "prov3", allowOverride: true })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count3', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count4', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count4', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { allowOverride: false, alias: "count4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count4', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count5', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count5', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { allowOverride: true, alias: "count5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count5', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count6', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count6', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "", allowOverride: true })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count6', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'count7', '((string | undefined) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'count7', '((string | undefined) | undefined)', [dumpAnnotation('Provide', { alias: "", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_count7', '(IProvideDecoratedVariable<(string | undefined)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_count7', '(boolean | undefined)')} @@ -203,9 +207,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test different @Provide annotation usage transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts index fd80e117210d403bf95ad8037b517f250ae42645..dab5e3f562a1584407bbd16d66d6638ef1173d28 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { Provide as Provide } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct PropParent extends CustomComponent { - public __initializeStruct(initializers: (__Options_PropParent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_PropParent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_provideVar1 = STATE_MGMT_FACTORY.makeProvide(this, "provideVar1", "provideVar1", ((({let gensym___181030638 = initializers; (((gensym___181030638) == (null)) ? undefined : gensym___181030638.provideVar1)})) ?? ("propVar1")), false); this.__backing_provideVar2 = STATE_MGMT_FACTORY.makeProvide(this, "provideVar2", "provideVar2", ((({let gensym___143944235 = initializers; @@ -119,30 +119,34 @@ function main() {} this.__backing_provideVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_PropParent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar1', '(string | undefined)', [dumpAnnotation('Provide', { alias: "provideVar1", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar1', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar2', '(number | undefined)', [dumpAnnotation('Provide', { alias: "provideVar2", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar2', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar3', '(boolean | undefined)', [dumpAnnotation('Provide', { alias: "provideVar3", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar3', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar4', '(undefined | undefined)', [dumpAnnotation('Provide', { alias: "provideVar4", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar4', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar5', '(null | undefined)', [dumpAnnotation('Provide', { alias: "provideVar5", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar5', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar5', '(boolean | undefined)')} @@ -155,9 +159,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Provide decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts index 240e5bdfb4fd9d936050935af05237d983e6d8a4..c20e97ac2c7a83bd8fe1a97dfa8e69709cf4c5e9 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class PropType extends BaseEnum { } public static getValueOf(name: String): PropType { - for (let i = 0;((i) < (PropType.#NamesArray.length));(++i)) { + for (let i = ((PropType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (PropType.#NamesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class PropType extends BaseEnum { } public static fromValue(value: int): PropType { - for (let i = 0;((i) < (PropType.#ValuesArray.length));(++i)) { + for (let i = ((PropType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (PropType.#ValuesArray[i]))) { return PropType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class PropType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_provideVar1 = STATE_MGMT_FACTORY.makeProvide(this, "provideVar1", "provideVar1", ((({let gensym___181030638 = initializers; (((gensym___181030638) == (null)) ? undefined : gensym___181030638.provideVar1)})) ?? (new Per(6))), false); this.__backing_provideVar2 = STATE_MGMT_FACTORY.makeProvide>(this, "provideVar2", "provideVar2", ((({let gensym___143944235 = initializers; @@ -280,58 +280,62 @@ final class PropType extends BaseEnum { this.__backing_provideVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar1', '(Per | undefined)', [dumpAnnotation('Provide', { alias: "provideVar1", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar1', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar2', '(Array | undefined)', [dumpAnnotation('Provide', { alias: "provideVar2", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar2', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar3', '(PropType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar3', '(PropType | undefined)', [dumpAnnotation('Provide', { alias: "provideVar3", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar3', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar4', '(Set | undefined)', [dumpAnnotation('Provide', { alias: "provideVar4", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar4', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar5', '(Array | undefined)', [dumpAnnotation('Provide', { alias: "provideVar5", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar5', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar6', '(Array | undefined)', [dumpAnnotation('Provide', { alias: "provideVar6", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar6', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar7', '(Array | undefined)', [dumpAnnotation('Provide', { alias: "provideVar7", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar7', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('Provide', { alias: "provideVar8", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar8', '(IProvideDecoratedVariable<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar9', '(Date | undefined)', [dumpAnnotation('Provide', { alias: "provideVar9", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar9', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar10', '(Map | undefined)', [dumpAnnotation('Provide', { alias: "provideVar10", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar10', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar11', '((string | number) | undefined)', [dumpAnnotation('Provide', { alias: "provideVar11", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar11', '(IProvideDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'provideVar12', '((Set | Per) | undefined)', [dumpAnnotation('Provide', { alias: "provideVar12", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_provideVar12', '(IProvideDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_provideVar12', '(boolean | undefined)')} @@ -344,9 +348,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Provide decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-to-consume.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-to-consume.test.ts index aeab2882e9a6155f0c59f50d8178b177e255b2aa..a37592d439218d229a1c4ededb491ed4de562d7a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-to-consume.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-to-consume.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -80,10 +80,10 @@ import { Consume as Consume, Provide as Provide } from "@ohos.arkui.stateManagem @Component() export interface __Options_Child { ${ignoreNewLines(` - num?: number; + @Consume() num?: number; @Consume() __backing_num?: number; __options_has_num?: boolean; - str?: string; + @Consume({value:"ss"}) str?: string; @Consume({value:"ss"}) __backing_str?: string; __options_has_str?: boolean; `)} @@ -92,10 +92,10 @@ import { Consume as Consume, Provide as Provide } from "@ohos.arkui.stateManagem @Component() export interface __Options_Parent { ${ignoreNewLines(` - num?: number; + @Provide({alias:"num"}) num?: number; @Provide({alias:"num"}) __backing_num?: number; __options_has_num?: boolean; - str?: string; + @Provide({alias:"ss"}) str?: string; @Provide({alias:"ss"}) __backing_str?: string; __options_has_str?: boolean; `)} @@ -112,7 +112,7 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -129,7 +129,7 @@ import { Consume as Consume, Provide as Provide } from "@ohos.arkui.stateManagem function main() {} @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = STATE_MGMT_FACTORY.makeConsume(this, "num", "num"); this.__backing_str = STATE_MGMT_FACTORY.makeConsume(this, "str", "ss"); } @@ -156,16 +156,17 @@ function main() {} this.__backing_str!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Child num: \${this.num}\`, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Child str: \${this.str}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -173,11 +174,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = STATE_MGMT_FACTORY.makeProvide(this, "num", "num", ((({let gensym___83257243 = initializers; (((gensym___83257243) == (null)) ? undefined : gensym___83257243.num)})) ?? (10)), false); this.__backing_str = STATE_MGMT_FACTORY.makeProvide(this, "str", "ss", ((({let gensym___249074315 = initializers; @@ -206,16 +210,17 @@ function main() {} this.__backing_str!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Parent num: \${this.num}\`, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`Parent str: \${this.str}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -226,26 +231,29 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_num', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_num', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'str', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'str', '(string | undefined)', [dumpAnnotation('Consume', { value: "ss" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_str', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_str', '(boolean | undefined)')} } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)', [dumpAnnotation('Provide', { alias: "num", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_num', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_num', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'str', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'str', '(string | undefined)', [dumpAnnotation('Provide', { alias: "ss", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_str', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_str', '(boolean | undefined)')} @@ -262,7 +270,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test usage of @Provide and @Consume decorator', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-basic-type.test.ts index ae8a373f218b6ce34e09e2639271745fc8cff280..029e06e4ff5ce4321c96d1072b7916dd60e7b486 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IConsumerDecoratedVariable as IConsumerDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -56,7 +56,7 @@ function main() {} @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_consumerVar1 = STATE_MGMT_FACTORY.makeConsumer(this, "consumerVar1", "consumerVar1", "propVar1"); this.__backing_consumerVar2 = STATE_MGMT_FACTORY.makeConsumer(this, "consumerVar2", "consumerVar2", 50); this.__backing_consumerVar3 = STATE_MGMT_FACTORY.makeConsumer(this, "consumerVar3", "consumerVar3", true); @@ -116,30 +116,34 @@ function main() {} this.__backing_consumerVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar1', '(string | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_consumerVar1', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_consumerVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar2', '(number | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_consumerVar2', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_consumerVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar3', '(boolean | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_consumerVar3', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_consumerVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar4', '(undefined | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_consumerVar4', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_consumerVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'consumerVar5', '(null | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_consumerVar5', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_consumerVar5', '(boolean | undefined)')} @@ -152,9 +156,9 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Consumer decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-complex-type.test.ts index 9d4a85feeb264725ff50dd8a468b39ce6ac0b6fe..9c8f9e07aae773c6379a8f86b5a318b5fb61a2a8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/consumer-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IConsumerDecoratedVariable as IConsumerDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -93,7 +93,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -102,7 +102,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -133,7 +133,7 @@ final class StateType extends BaseEnum { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_paramVar1 = STATE_MGMT_FACTORY.makeConsumer(this, "paramVar1", "paramVar1", new Per(6)); this.__backing_paramVar2 = STATE_MGMT_FACTORY.makeConsumer>(this, "paramVar2", "paramVar2", new Array(3, 6, 8)); this.__backing_paramVar3 = STATE_MGMT_FACTORY.makeConsumer(this, "paramVar3", "paramVar3", StateType.TYPE3); @@ -259,54 +259,58 @@ final class StateType extends BaseEnum { this.__backing_paramVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar1', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar2', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar3', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar4', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar5', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar6', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar7', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar9', '(IConsumerDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar10', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar11', '(IConsumerDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar12', '(IConsumerDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar12', '(boolean | undefined)')} @@ -319,9 +323,9 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Consumer decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-basic-type.test.ts index bb310da781e7854a92562898a2815b37b2c232ce..27ae954f693c51186c9724d08ae928d3fedaaadc 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProviderDecoratedVariable as IProviderDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -56,7 +56,7 @@ function main() {} @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_providerVar1 = STATE_MGMT_FACTORY.makeProvider(this, "providerVar1", "providerVar1", "propVar1"); this.__backing_providerVar2 = STATE_MGMT_FACTORY.makeProvider(this, "providerVar2", "providerVar2", 50); this.__backing_providerVar3 = STATE_MGMT_FACTORY.makeProvider(this, "providerVar3", "providerVar3", true); @@ -116,30 +116,34 @@ function main() {} this.__backing_providerVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar1', '(string | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providerVar1', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providerVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar2', '(number | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providerVar2', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providerVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar3', '(boolean | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providerVar3', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providerVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar4', '(undefined | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providerVar4', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providerVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providerVar5', '(null | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providerVar5', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providerVar5', '(boolean | undefined)')} @@ -152,9 +156,9 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Provider decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-complex-type.test.ts index 25fd1cca80da697088fbbdc3ea8e36d217ff9f71..b4d6903d9944e890c18324ed6d90e0ef987390d8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { IProviderDecoratedVariable as IProviderDecoratedVariable } from "arkui.stateManagement.decorator"; @@ -93,7 +93,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -102,7 +102,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -133,7 +133,7 @@ final class StateType extends BaseEnum { } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_paramVar1 = STATE_MGMT_FACTORY.makeProvider(this, "paramVar1", "paramVar1", new Per(6)); this.__backing_paramVar2 = STATE_MGMT_FACTORY.makeProvider>(this, "paramVar2", "paramVar2", new Array(3, 6, 8)); this.__backing_paramVar3 = STATE_MGMT_FACTORY.makeProvider(this, "paramVar3", "paramVar3", StateType.TYPE3); @@ -259,54 +259,58 @@ final class StateType extends BaseEnum { this.__backing_paramVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar1', '(Per | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar1', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar2', '(Array | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar2', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar3', '(StateType | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar3', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar4', '(Set | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar4', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar5', '(Array | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar5', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar6', '(Array | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar6', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar7', '(Array | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar7', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar9', '(Date | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar9', '(IProviderDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar10', '(Map | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar10', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar11', '((string | number) | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar11', '(IProviderDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'paramVar12', '((Set | Per) | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_paramVar12', '(IProviderDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_paramVar12', '(boolean | undefined)')} @@ -319,9 +323,9 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Provider decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testCheckedTransformer], + 'checked:ui-no-recheck': [testCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts index 382a438b5ba1f0924500c14a12fa1785bfab0d17..e5317e9a5f0936787912b3db28d68ebd01ff22b6 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/provider-and-consumer/provider-to-consumer.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -57,7 +57,7 @@ import { IProviderDecoratedVariable as IProviderDecoratedVariable } from "arkui. import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -111,8 +111,7 @@ function main() {} @JSONRename({newName:"name"}) private __backing_name?: string; @JSONStringifyIgnore() @JSONParseIgnore() private __meta_name: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - @JSONRename({newName:"age"}) private __backing_age?: number; - @JSONStringifyIgnore() @JSONParseIgnore() private __meta_age: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get name(): string { this.conditionalAddRef(this.__meta_name); return UIUtils.makeObserved((this.__backing_name as string)); @@ -125,7 +124,10 @@ function main() {} this.executeOnSubscribingWatches("name"); } } - + + @JSONRename({newName:"age"}) private __backing_age?: number; + @JSONStringifyIgnore() @JSONParseIgnore() private __meta_age: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + public get age(): number { this.conditionalAddRef(this.__meta_age); return UIUtils.makeObserved((this.__backing_age as number)); @@ -143,11 +145,14 @@ function main() {} this.name = name; this.age = age; } + + static { + } } @ComponentV2() final struct Parent extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_users = STATE_MGMT_FACTORY.makeProvider>(this, "users", "data", data); } @@ -162,27 +167,28 @@ function main() {} this.__backing_users!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), undefined, undefined, undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("add new user", undefined).onClick(((e) => { this.users.push(new User("Molly", 18)); })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("age++", undefined).onClick(((e) => { (this.users[0].age++); })).applyAttributesFinish(); return; }), undefined); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("change name", undefined).onClick(((e) => { this.users[0].name = "Shelly"; })).applyAttributesFinish(); @@ -192,11 +198,14 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() final struct Child extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_users = STATE_MGMT_FACTORY.makeConsumer>(this, "users", "data", []); } @@ -211,28 +220,29 @@ function main() {} this.__backing_users!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + }), @Memo() (() => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return this.users; - }), @memo() ((item: User) => { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + }), ((item: User) => { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`name: \${item.name}\`, undefined).fontSize(30).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`age: \${item.age}\`, undefined).fontSize(30).applyAttributesFinish(); return; }), undefined); - DividerImpl(@memo() ((instance: DividerAttribute): void => { + DividerImpl(@Memo() ((instance: DividerAttribute): void => { instance.setDividerOptions().applyAttributesFinish(); return; })); @@ -244,18 +254,21 @@ function main() {} } public constructor() {} + + static { + } } @ComponentV2() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'users', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'users', '(Array | undefined)', [dumpAnnotation('Provider', { value: "data" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_users', '(IProviderDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_users', '(boolean | undefined)')} } @ComponentV2() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'users', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'users', '(Array | undefined)', [dumpAnnotation('Consumer', { value: "data" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_users', '(IConsumerDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_users', '(boolean | undefined)')} @@ -268,7 +281,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test usage of @Provider and @Consumer decorator', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/regular/readonly-regular.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/regular/readonly-regular.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..da88867f30633dd82c9826632ff242324d6ceda4 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/regular/readonly-regular.test.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 path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const REGULAR_DIR_PATH: string = 'decorators/regular'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, REGULAR_DIR_PATH, 'readonly-regular.ets'), +]; + +const parsedTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed, +} + +const pluginTester = new PluginTester('test readonly regular variables transformation', buildConfig); + +const expectedScript: string = ` +function main() {} +@ComponentV2() final struct Child extends CustomComponentV2 { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { + this.__backing_readOnlyParam = ((({let gensym___ = initializers; + (((gensym___) == (null)) ? undefined : gensym___.readOnlyParam)})) ?? (0)); + } + + public __updateStruct(initializers: (__Options_Child | undefined)): void {} + + private __backing_readOnlyParam?: number; + + public get readOnlyParam(): number { + return (this.__backing_readOnlyParam as number); + } + public set readOnlyParam(value: number) { + this.__backing_readOnlyParam = value; + } + + @Memo() + public build() {} + + public constructor() {} + + static { + + } +} +@ComponentV2() export interface __Options_Child { + ${dumpGetterSetter(GetSetDumper.BOTH, 'readOnlyParam', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_readOnlyParam', '(boolean | undefined)')} +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test readonly regular variables transformation', + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/require/basic-require.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/require/basic-require.test.ts index 9c28297301454ba701e4286c0c5dab8eb94152db..a50c2ba5d6c25ca8b7cab492a9404d1134eb9b83 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/require/basic-require.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/require/basic-require.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, uiNoRecheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -84,30 +84,30 @@ import { State as State, Require as Require, PropRef as PropRef, Provide as Prov ${ignoreNewLines(` hello?: string; __options_has_hello?: boolean; - state1?: boolean; + @State() state1?: boolean; @State() __backing_state1?: boolean; __options_has_state1?: boolean; - select100?: string; + @Require() select100?: string; __options_has_select100?: boolean; - select0?: number; - @Require() @State() __backing_select0?: number; + @State() @Require() select0?: number; + @State() __backing_select0?: number; __options_has_select0?: boolean; - select3?: (number | null); - @Require() @State() __backing_select3?: (number | null); + @State() @Require() select3?: (number | null); + @State() __backing_select3?: (number | null); __options_has_select3?: boolean; - select4?: undefined; - @Require() @State() __backing_select4?: undefined; + @State() @Require() select4?: undefined; + @State() __backing_select4?: undefined; __options_has_select4?: boolean; - select1?: string; - @Require() @PropRef() __backing_select1?: string; + @PropRef() @Require() select1?: string; + @PropRef() __backing_select1?: string; __options_has_select1?: boolean; - select2?: string[]; - @Require() @Provide({alias:"15"}) __backing_select2?: string[]; + @Provide({alias:"15"}) @Require() select2?: string[]; + @Provide({alias:"15"}) __backing_select2?: string[]; __options_has_select2?: boolean; - select6?: (string[] | undefined | string); - @Require() @Provide({alias:"t"}) __backing_select6?: (string[] | undefined | string); + @Provide({alias:"t"}) @Require() select6?: (string[] | undefined | string); + @Provide({alias:"t"}) __backing_select6?: (string[] | undefined | string); __options_has_select6?: boolean; - @BuilderParam() builder?: (()=> void); + @BuilderParam() @Require() builder?: (()=> void); __options_has_builder?: boolean; `)} @@ -115,8 +115,8 @@ import { State as State, Require as Require, PropRef as PropRef, Provide as Prov @ComponentV2() export interface __Options_V2222 { ${ignoreNewLines(` - select1?: string; - @Require() @Param() __backing_select1?: string; + @Param() @Require() select1?: string; + @Param() __backing_select1?: string; __options_has_select1?: boolean; `)} @@ -129,7 +129,7 @@ import { IProvideDecoratedVariable as IProvideDecoratedVariable } from "arkui.st import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Component as Component, ComponentV2 as ComponentV2, BuilderParam as BuilderParam } from "@ohos.arkui.component"; @@ -138,7 +138,7 @@ import { State as State, Require as Require, PropRef as PropRef, Provide as Prov function main() {} @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_hello = ((({let gensym___159351621 = initializers; (((gensym___159351621) == (null)) ? undefined : gensym___159351621.hello)})) ?? ("hello")); this.__backing_state1 = STATE_MGMT_FACTORY.makeState(this, "state1", ((({let gensym___152317197 = initializers; @@ -252,24 +252,28 @@ function main() {} this.__backing_select6!.set(value); } - private __backing_builder?: @memo() (()=> void); + private __backing_builder?: @Memo() (()=> void); - public get builder(): @memo() (()=> void) { + public get builder(): @Memo() (()=> void) { return this.__backing_builder!; } - public set builder(value: @memo() (()=> void)) { + public set builder(value: @Memo() (()=> void)) { this.__backing_builder = value; } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @ComponentV2() final struct V2222 extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_V2222 | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_V2222 | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_select1 = STATE_MGMT_FACTORY.makeParam(this, "select1", (initializers!.select1 as string)); } @@ -286,55 +290,59 @@ function main() {} return this.__backing_select1!.get(); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { ${dumpGetterSetter(GetSetDumper.BOTH, 'hello', '(string | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_hello', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'state1', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'state1', '(boolean | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_state1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_state1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select100', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select100', '(string | undefined)', [dumpAnnotation('Require')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select100', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select0', '(number | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select0', '(IStateDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select0', '(number | undefined)', [dumpAnnotation('State'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select0', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select0', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select3', '((number | null) | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select3', '(IStateDecoratedVariable<(number | null)> | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select3', '((number | null) | undefined)', [dumpAnnotation('State'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select3', '(IStateDecoratedVariable<(number | null)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select4', '(undefined | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select4', '(IStateDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select4', '(undefined | undefined)', [dumpAnnotation('State'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select4', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select1', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select1', '(IPropRefDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select1', '(string | undefined)', [dumpAnnotation('PropRef'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select1', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select2', '(Array | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select2', '(IProvideDecoratedVariable> | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select2', '(Array | undefined)', [dumpAnnotation('Provide', { alias: "15", allowOverride: false }), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select2', '(IProvideDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'select6', '((Array | undefined | string) | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select6', '(IProvideDecoratedVariable<(Array | undefined | string)> | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select6', '((Array | undefined | string) | undefined)', [dumpAnnotation('Provide', { alias: "t", allowOverride: false }), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select6', '(IProvideDecoratedVariable<(Array | undefined | string)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builder', '(@memo() (()=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builder', '(@Memo() (()=> void) | undefined)', [dumpAnnotation('Require')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builder', '(boolean | undefined)')} } @ComponentV2() export interface __Options_V2222 { - ${dumpGetterSetter(GetSetDumper.BOTH, 'select1', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select1', '(IParamDecoratedVariable | undefined)', [dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select1', '(string | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Require')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select1', '(IParamDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select1', '(boolean | undefined)')} } @@ -350,7 +358,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Require decorator capability', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed': [testParsedTransformer], 'checked:ui-no-recheck': [testCheckedTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts index 57522d281fd30cba04a0acc2dc1b654a0992683c..3718b6c7c0099848ba9200efc30082a519e4eea0 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -59,7 +59,7 @@ import { ImageAttribute as ImageAttribute } from "arkui.component.image"; import { ImageImpl as ImageImpl } from "arkui.component.image"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -77,7 +77,7 @@ import { Component as Component, $r as $r, $rawfile as $rawfile, Column as Colum function main() {} @Component() final struct ResourceComponent extends CustomComponent { - public __initializeStruct(initializers: (__Options_ResourceComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_ResourceComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_str1 = ((({let gensym___147578113 = initializers; (((gensym___147578113) == (null)) ? undefined : gensym___147578113.str1)})) ?? ("app.media.ri")); this.__backing_str2 = ((({let gensym___220149772 = initializers; @@ -132,34 +132,35 @@ function main() {} const a2 = await this.test_0(_r(16777216, 10003, "com.example.mock", "entry")); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(_r(16777216, 10003, "com.example.mock", "entry"), undefined).applyAttributesFinish(); return; }), undefined); - ImageImpl(@memo() ((instance: ImageAttribute): void => { + ImageImpl(@Memo() ((instance: ImageAttribute): void => { instance.setImageOptions(_rawfile(0, 30000, "com.example.mock", "entry", "app.mock.txt"), undefined).applyAttributesFinish(); return; }), undefined); - TextInputImpl(@memo() ((instance: TextInputAttribute): void => { + TextInputImpl(@Memo() ((instance: TextInputAttribute): void => { instance.setTextInputOptions({ text: _r(16777220, 10003, "com.example.mock", "entry"), }).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(_r(-1, -1, "com.example.mock", "entry", this.str1), undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(_r(-1, -1, "com.example.mock", "entry", this.str2), undefined).applyAttributesFinish(); return; }), undefined); - SelectImpl(@memo() ((instance: SelectAttribute): void => { + SelectImpl(@Memo() ((instance: SelectAttribute): void => { instance.setSelectOptions(new Array({ value: "aaa", icon: _r(16777223, 20000, "com.example.mock", "entry"), @@ -175,14 +176,14 @@ function main() {} })).applyAttributesFinish(); return; }), undefined); - ImageImpl(@memo() ((instance: ImageAttribute): void => { + ImageImpl(@Memo() ((instance: ImageAttribute): void => { instance.setImageOptions(_r(16777217, 20000, "com.example.mock", "entry"), undefined).margin(({ top: _r(16777222, 10002, "com.example.mock", "entry"), bottom: _r(16777222, 10002, "com.example.mock", "entry"), } as Margin)).applyAttributesFinish(); return; }), undefined); - ImageAnimatorImpl(@memo() ((instance: ImageAnimatorAttribute): void => { + ImageAnimatorImpl(@Memo() ((instance: ImageAnimatorAttribute): void => { instance.setImageAnimatorOptions().images([{ src: _r(16777217, 20000, "com.example.mock", "entry"), }, { @@ -194,7 +195,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_ResourceComponent { @@ -216,7 +220,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test resource transform in build method', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts index 46f18e05f275044c4737b1df721e31d29fffd366..77c671801c1143fff7b009e6397c6c826da2c7b5 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -42,7 +42,7 @@ const expectedScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ImageAttribute as ImageAttribute } from "arkui.component.image"; import { ImageImpl as ImageImpl } from "arkui.component.image"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -57,7 +57,7 @@ function main() {} i = _r(16777216, 10003, "com.example.mock", "entry"); @Component() final struct ResourceComponent extends CustomComponent { - public __initializeStruct(initializers: (__Options_ResourceComponent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_ResourceComponent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_str = ((({let gensym___42103502 = initializers; (((gensym___42103502) == (null)) ? undefined : gensym___42103502.str)})) ?? (_r(16777216, 10003, "com.example.mock", "entry"))); this.__backing_icon = ((({let gensym___38135554 = initializers; @@ -99,27 +99,31 @@ i = _r(16777216, 10003, "com.example.mock", "entry"); this.__backing_lambdaOne = value; } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(this.str, undefined).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(i, undefined).applyAttributesFinish(); return; }), undefined); - ImageImpl(@memo() ((instance: ImageAttribute): void => { + ImageImpl(@Memo() ((instance: ImageAttribute): void => { instance.setImageOptions(this.icon, undefined).applyAttributesFinish(); return; }), undefined); })); } public constructor() {} + + static { + } } @Component() export interface __Options_ResourceComponent { @@ -143,7 +147,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test resource transform in property', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index 9b37af82085df387b41371fec843f6c9fa38a63d..c3ebfd75218fd675bcb9bd2fb867bce49e36f51a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -45,7 +45,7 @@ import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement. import { IPropRefDecoratedVariable as IPropRefDecoratedVariable } from "arkui.stateManagement.decorator"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -56,11 +56,12 @@ import { State as State, PropRef as PropRef } from "@ohos.arkui.stateManagement" function main() {} @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} - @memo() public build() { + @Memo() + public build() { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -70,11 +71,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() @Reusable() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_num = STATE_MGMT_FACTORY.makePropRef(this, "num", ((({let gensym___83257243 = initializers; (((gensym___83257243) == (null)) ? undefined : gensym___83257243.num)})) ?? (1))); this.__backing_num1 = STATE_MGMT_FACTORY.makeState(this, "num1", ((({let gensym___24398512 = initializers; @@ -116,10 +120,14 @@ function main() {} this.__backing_num1!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { @@ -127,11 +135,11 @@ function main() {} } @Component() @Reusable() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'num', '(number | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_num', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_num', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'num1', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'num1', '(number | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_num1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_num1', '(boolean | undefined)')} @@ -144,7 +152,7 @@ function testReusableTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic reusable', - [reusableTransform, uiNoRecheck, recheck], + [reusableTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testReusableTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts index 00107f09988a1d6eba38983535a6189d445cb273..9d21c571b9ac6a37ed81f83ea117f377d1ea60ad 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -53,7 +53,7 @@ import { ConditionScope as ConditionScope } from "arkui.component.builder"; import { ConditionBranch as ConditionBranch } from "arkui.component.builder"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -93,7 +93,7 @@ class Message { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_display = STATE_MGMT_FACTORY.makeState(this, "display", ((({let gensym___83835842 = initializers; (((gensym___83835842) == (null)) ? undefined : gensym___83835842.display)})) ?? (true))); } @@ -110,20 +110,21 @@ class Message { this.__backing_display!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).height("100%").width("100%").applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("Hello", undefined).fontSize(30).fontWeight(FontWeight.Bold).onClick(((e: ClickEvent) => { this.display = !(this.display); })).applyAttributesFinish(); return; }), undefined); - ConditionScope(@memo() (() => { + ConditionScope(@Memo() (() => { if (this.display) { - ConditionBranch(@memo() (() => { + ConditionBranch(@Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -137,11 +138,14 @@ class Message { } public constructor() {} + + static { + } } @Reusable() @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeState(this, "message", ((({let gensym___91869411 = initializers; (((gensym___91869411) == (null)) ? undefined : gensym___91869411.message)})) ?? (new Message("AboutToReuse")))); } @@ -167,12 +171,13 @@ class Message { public aboutToReuse(params: Record) {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).borderWidth(1).height(100).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(this.message.value, undefined).fontSize(30).applyAttributesFinish(); return; }), undefined); @@ -180,11 +185,15 @@ class Message { } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); }), undefined, undefined, undefined); @@ -195,14 +204,14 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'display', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'display', '(boolean | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_display', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_display', '(boolean | undefined)')} } @Reusable() @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(Message | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(Message | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} @@ -215,7 +224,7 @@ function testReusableTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex reusable', - [reusableTransform, uiNoRecheck, recheck], + [reusableTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testReusableTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts index 09b0495509c2202fc7d98b752c1921aaf5062789..f98858eb2351e7391a8297ee204428165df840ce 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { State as State } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_stateVar1 = STATE_MGMT_FACTORY.makeState(this, "stateVar1", ((({let gensym___213853607 = initializers; (((gensym___213853607) == (null)) ? undefined : gensym___213853607.stateVar1)})) ?? ("stateVar1"))); this.__backing_stateVar2 = STATE_MGMT_FACTORY.makeState(this, "stateVar2", ((({let gensym___113574154 = initializers; @@ -119,30 +119,34 @@ function main() {} this.__backing_stateVar5!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(number | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar2', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(boolean | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar3', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(undefined | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar4', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(null | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar5', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar5', '(boolean | undefined)')} @@ -155,9 +159,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @State decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts index d6661d5fb8ff29a7ffda37980fa83bac2f0d69b5..597c9b9e8b3ea8b4bbc0a1393f584f2a2f6df6fc 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { structNoRecheck, recheck, beforeUINoRecheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -91,7 +91,7 @@ final class StateType extends BaseEnum { } public static getValueOf(name: String): StateType { - for (let i = 0;((i) < (StateType.#NamesArray.length));(++i)) { + for (let i = ((StateType.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (StateType.#NamesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -100,7 +100,7 @@ final class StateType extends BaseEnum { } public static fromValue(value: int): StateType { - for (let i = 0;((i) < (StateType.#ValuesArray.length));(++i)) { + for (let i = ((StateType.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (StateType.#ValuesArray[i]))) { return StateType.#ItemsArray[i]; } @@ -131,7 +131,7 @@ final class StateType extends BaseEnum { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_stateVar1 = STATE_MGMT_FACTORY.makeState(this, "stateVar1", ((({let gensym___213853607 = initializers; (((gensym___213853607) == (null)) ? undefined : gensym___213853607.stateVar1)})) ?? (new Per(6)))); this.__backing_stateVar2 = STATE_MGMT_FACTORY.makeState>(this, "stateVar2", ((({let gensym___113574154 = initializers; @@ -280,58 +280,62 @@ final class StateType extends BaseEnum { this.__backing_stateVar12!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar1', '(Per | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar1', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar2', '(Array | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar2', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(StateType | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar3', '(StateType | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar3', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar4', '(Set | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar4', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar4', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar5', '(Array | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar5', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar5', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar6', '(Array | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar6', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar6', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar7', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar7', '(Array | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar7', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar7', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(((sr: string)=> void) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar8', '(((sr: string)=> void) | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar8', '(IStateDecoratedVariable<((sr: string)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar8', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar9', '(Date | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar9', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar9', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar10', '(Map | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar10', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar10', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '((string | number) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar11', '((string | number) | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar11', '(IStateDecoratedVariable<(string | number)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar11', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '((Set | Per) | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stateVar12', '((Set | Per) | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stateVar12', '(IStateDecoratedVariable<(Set | Per)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stateVar12', '(boolean | undefined)')} @@ -344,9 +348,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @State decorated variables transformation', - [parsedTransform, structNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { - 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts index c9198623466bce577867bb09e6266a7de3bdd5c2..5a9db789610341b3deedb7a9f38aa7a411d76564 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -49,7 +49,7 @@ import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -71,7 +71,7 @@ class Per { } @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_parentVar1 = STATE_MGMT_FACTORY.makeState(this, "parentVar1", ((({let gensym___247315634 = initializers; (((gensym___247315634) == (null)) ? undefined : gensym___247315634.parentVar1)})) ?? (new Per("hello")))); } @@ -88,11 +88,12 @@ class Per { this.__backing_parentVar1!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), { @@ -103,11 +104,14 @@ class Per { } public constructor() {} + + static { + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_childVar1 = STATE_MGMT_FACTORY.makeState(this, "childVar1", ((({let gensym___218939886 = initializers; (((gensym___218939886) == (null)) ? undefined : gensym___218939886.childVar1)})) ?? (new Per("ccc")))); } @@ -124,26 +128,30 @@ class Per { this.__backing_childVar1!.set(value); } - @memo() public build() { - TextImpl(@memo() ((instance: TextAttribute): void => { + @Memo() + public build() { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(this.childVar1.str, undefined).applyAttributesFinish(); return; }), undefined); } public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'parentVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'parentVar1', '(Per | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_parentVar1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_parentVar1', '(boolean | undefined)')} } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'childVar1', '(Per | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'childVar1', '(Per | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_childVar1', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_childVar1', '(boolean | undefined)')} @@ -156,7 +164,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @State decorated variables passing', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts index f21284e2520f2a715c0b19f5213a46f4f6e1fb3b..0a039dd600446694132a8e73384da8c9147fb3c9 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -42,7 +42,7 @@ const expectedScript: string = ` import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IStorageLinkDecoratedVariable as IStorageLinkDecoratedVariable } from "arkui.stateManagement.decorator"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -74,7 +74,7 @@ class Data { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_storageLink = STATE_MGMT_FACTORY.makeStorageLink(this, "PropA", "storageLink", 1); this.__backing_storageLinkObject = STATE_MGMT_FACTORY.makeStorageLink(this, "PropB", "storageLinkObject", new Data(1)); } @@ -101,18 +101,19 @@ class Data { this.__backing_storageLinkObject!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`From AppStorage \${this.storageLink}\`, undefined).onClick(((e: ClickEvent) => { this.storageLink += 1; })).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`From AppStorage \${this.storageLinkObject.code}\`, undefined).onClick(((e: ClickEvent) => { this.storageLinkObject.code += 1; })).applyAttributesFinish(); @@ -122,11 +123,15 @@ class Data { } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); }), undefined, undefined, undefined); @@ -137,11 +142,11 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'storageLink', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'storageLink', '(number | undefined)', [dumpAnnotation('StorageLink', { value: "PropA" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storageLink', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_storageLink', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'storageLinkObject', '(Data | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'storageLinkObject', '(Data | undefined)', [dumpAnnotation('StorageLink', { value: "PropB" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storageLinkObject', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_storageLinkObject', '(boolean | undefined)')} @@ -154,7 +159,7 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink with appstorage', - [storageLinkTransform, uiNoRecheck, recheck], + [storageLinkTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStorageLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts index 55f06fd3312f36caa0fe05f78fcccda0c3549361..a370de2ae1f0a4625cd040ee194094bab88f137f 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storageLinkTransform: Plugins = { const pluginTester = new PluginTester('test storagelink complex type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IStorageLinkDecoratedVariable as IStorageLinkDecoratedVariable } from "arkui.stateManagement.decorator"; import { NavInterface as NavInterface } from "arkui.component.customComponent"; @@ -95,7 +95,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -104,7 +104,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -135,7 +135,7 @@ final class Status extends BaseEnum { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_arrayA = STATE_MGMT_FACTORY.makeStorageLink>(this, "Prop1", "arrayA", [1, 2, 3]); this.__backing_objectA = STATE_MGMT_FACTORY.makeStorageLink(this, "Prop2", "objectA", {}); this.__backing_dateA = STATE_MGMT_FACTORY.makeStorageLink(this, "Prop3", "dateA", new Date("2021-08-08")); @@ -217,14 +217,19 @@ final class Status extends BaseEnum { this.__backing_enumA!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -235,31 +240,31 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayA', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayA', '(Array | undefined)', [dumpAnnotation('StorageLink', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_arrayA', '(IStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_arrayA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectA', '(Object | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectA', '(Object | undefined)', [dumpAnnotation('StorageLink', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'dateA', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'dateA', '(Date | undefined)', [dumpAnnotation('StorageLink', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_dateA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_dateA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'setA', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'setA', '(Set | undefined)', [dumpAnnotation('StorageLink', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_setA', '(IStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_setA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'mapA', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'mapA', '(Map | undefined)', [dumpAnnotation('StorageLink', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_mapA', '(IStorageLinkDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_mapA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'classA', '(Person | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'classA', '(Person | undefined)', [dumpAnnotation('StorageLink', { value: "Prop7" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_classA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_classA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'enumA', '(Status | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'enumA', '(Status | undefined)', [dumpAnnotation('StorageLink', { value: "Prop8" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_enumA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_enumA', '(boolean | undefined)')} @@ -272,7 +277,7 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink complex type transform', - [storageLinkTransform, uiNoRecheck, recheck], + [storageLinkTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStorageLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts index f7588f0ec7dd587490dea5d96238a2c2ae763478..a85279249edaefdbbe093f9fdb6f1ff84990cd87 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storageLinkTransform: Plugins = { const pluginTester = new PluginTester('test storagelink primitive type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IStorageLinkDecoratedVariable as IStorageLinkDecoratedVariable } from "arkui.stateManagement.decorator"; import { NavInterface as NavInterface } from "arkui.component.customComponent"; @@ -60,7 +60,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_numA = STATE_MGMT_FACTORY.makeStorageLink(this, "Prop1", "numA", 33); this.__backing_stringA = STATE_MGMT_FACTORY.makeStorageLink(this, "Prop2", "stringA", "AA"); this.__backing_booleanA = STATE_MGMT_FACTORY.makeStorageLink(this, "Prop3", "booleanA", true); @@ -98,14 +98,19 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_booleanA!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -116,15 +121,15 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'numA', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'numA', '(number | undefined)', [dumpAnnotation('StorageLink', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_numA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_numA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stringA', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stringA', '(string | undefined)', [dumpAnnotation('StorageLink', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stringA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stringA', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanA', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanA', '(boolean | undefined)', [dumpAnnotation('StorageLink', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_booleanA', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_booleanA', '(boolean | undefined)')} @@ -137,7 +142,7 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink primitive type transform', - [storageLinkTransform, uiNoRecheck, recheck], + [storageLinkTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStorageLinkTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts index f7b381584eab9530d5839e792102c5e4237044da..03bb53c82d7ad808aeab6575c4898bd2611202fb 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-complex-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test @StoragePropRef complex type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -89,7 +89,7 @@ final class Status extends BaseEnum { } public static getValueOf(name: String): Status { - for (let i = 0;((i) < (Status.#NamesArray.length));(++i)) { + for (let i = ((Status.#NamesArray.length) - (1));((i) >= (0));(--i)) { if (((name) == (Status.#NamesArray[i]))) { return Status.#ItemsArray[i]; } @@ -98,7 +98,7 @@ final class Status extends BaseEnum { } public static fromValue(value: int): Status { - for (let i = 0;((i) < (Status.#ValuesArray.length));(++i)) { + for (let i = ((Status.#ValuesArray.length) - (1));((i) >= (0));(--i)) { if (((value) == (Status.#ValuesArray[i]))) { return Status.#ItemsArray[i]; } @@ -129,7 +129,7 @@ final class Status extends BaseEnum { } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_arrayB = STATE_MGMT_FACTORY.makeStoragePropRef>(this, "Prop1", "arrayB", [1, 2, 3]); this.__backing_objectB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop2", "objectB", {}); this.__backing_dateB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop3", "dateB", new Date("2021-09-09")); @@ -211,38 +211,42 @@ final class Status extends BaseEnum { this.__backing_enumB!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayB', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'arrayB', '(Array | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_arrayB', '(IStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_arrayB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectB', '(Object | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectB', '(Object | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'dateB', '(Date | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'dateB', '(Date | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_dateB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_dateB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'setB', '(Set | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'setB', '(Set | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_setB', '(IStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_setB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'mapB', '(Map | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'mapB', '(Map | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_mapB', '(IStoragePropRefDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_mapB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'classB', '(Person | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'classB', '(Person | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop7" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_classB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_classB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'enumB', '(Status | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'enumB', '(Status | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop8" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_enumB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_enumB', '(boolean | undefined)')} @@ -255,7 +259,7 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test @StoragePropRef complex type transform', - [storagePropTransform, uiNoRecheck, recheck], + [storagePropTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStoragePropTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts index fb6d5547254b1efb9543520b3418391e980686fa..b3d813a3a0ca191ed4cd8a4e242035ce708e15d7 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/storageprop-ref/storageprop-ref-primitive-type.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -39,7 +39,7 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test @StoragePropRef primitive type transform', buildConfig); const expectedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; @@ -54,7 +54,7 @@ import { StoragePropRef as StoragePropRef } from "@ohos.arkui.stateManagement"; function main() {} @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_numB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop1", "numB", 43); this.__backing_stringB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop2", "stringB", "BB"); this.__backing_booleanB = STATE_MGMT_FACTORY.makeStoragePropRef(this, "Prop3", "booleanB", false); @@ -114,30 +114,34 @@ function main() {} this.__backing_nullB!.set(value); } - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'numB', '(number | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'numB', '(number | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop1" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_numB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_numB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'stringB', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'stringB', '(string | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop2" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_stringB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_stringB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanB', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'booleanB', '(boolean | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop3" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_booleanB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_booleanB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'undefinedB', '(undefined | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'undefinedB', '(undefined | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop4" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_undefinedB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_undefinedB', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'nullB', '(null | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'nullB', '(null | undefined)', [dumpAnnotation('StoragePropRef', { value: "Prop5" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_nullB', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_nullB', '(boolean | undefined)')} @@ -150,7 +154,7 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test @StoragePropRef primitive type transform', - [storagePropTransform, uiNoRecheck, recheck], + [storagePropTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testStoragePropTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts index 9e3e87a810774de403011f1cfbf0d6f47740ba11..90478c0e3c40a9201b9727721f7f9fc7a93f5cfe 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../../utils/simplify-dump'; import { uiTransform } from '../../../../../ui-plugins'; @@ -59,7 +59,7 @@ import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateM import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; @@ -132,8 +132,6 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ @JSONStringifyIgnore() @JSONParseIgnore() private __meta_trackA: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); - public constructor() {} - public get trackA(): string { this.conditionalAddRef(this.__meta_trackA); return this.__backing_trackA; @@ -146,11 +144,16 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.executeOnSubscribingWatches("trackA"); } } + + public constructor() {} + + static { + } } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_statevar = STATE_MGMT_FACTORY.makeState(this, "statevar", ((({let gensym___76198660 = initializers; (((gensym___76198660) == (null)) ? undefined : gensym___76198660.statevar)})) ?? ("Hello World")), ((_: string): void => { this.stateOnChange(_); @@ -272,11 +275,12 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ public ProvideOnChange(propName: string) {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { Child._instantiateImpl(undefined, (() => { return new Child(); }), undefined, undefined, undefined); @@ -284,11 +288,14 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } @Component() final struct Child extends CustomComponent { - public __initializeStruct(initializers: (__Options_Child | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Child | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_providevar = STATE_MGMT_FACTORY.makeConsume(this, "providevar", "providevar", ((_: string): void => { this.ConsumeOnChange(_); })); @@ -308,16 +315,19 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ public ConsumeOnChange(propName: string) {} - @memo() public build() {} + @Memo() + public build() {} public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} - class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -328,39 +338,39 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'statevar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_statevar', '(IStateDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'stateOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'statevar', '(string | undefined)', [dumpAnnotation('State'), dumpAnnotation('Watch', { value: 'stateOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_statevar', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_statevar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'propvar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propvar', '(IPropRefDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'propOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'propvar', '(string | undefined)', [dumpAnnotation('Watch', { value: 'propOnChange' }), dumpAnnotation('PropRef')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_propvar', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_propvar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'linkvar', '(string | undefined)', [dumpAnnotation('__Link_intrinsic')])} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkvar', '(LinkSourceType | undefined)', [dumpAnnotation('Watch', { value: 'linkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'linkvar', '(string | undefined)', [dumpAnnotation('Link'), dumpAnnotation('Watch', { value: 'linkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_linkvar', '(LinkSourceType | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_linkvar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'storagelinkvar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storagelinkvar', '(IStorageLinkDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'storageLinkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'storagelinkvar', '(string | undefined)', [dumpAnnotation('StorageLink', { value: 'prop1' }), dumpAnnotation('Watch', { value: 'storageLinkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storagelinkvar', '(IStorageLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_storagelinkvar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'storagepropvar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storagepropvar', '(IStoragePropRefDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'storagePropOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'storagepropvar', '(string | undefined)', [dumpAnnotation('Watch', { value: 'storagePropOnChange' }), dumpAnnotation('StoragePropRef', { value: 'prop2' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_storagepropvar', '(IStoragePropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_storagepropvar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar', '(A | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar', '(IObjectLinkDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'objectLinkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'objectlinkvar', '(A | undefined)', [dumpAnnotation('ObjectLink'), dumpAnnotation('Watch', { value: 'objectLinkOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_objectlinkvar', '(IObjectLinkDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_objectlinkvar', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'providevar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providevar', '(IProvideDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'ProvideOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providevar', '(string | undefined)', [dumpAnnotation('Provide', { alias: "providevar", allowOverride: false }), dumpAnnotation('Watch', { value: 'ProvideOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providevar', '(IProvideDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providevar', '(boolean | undefined)')} } @Component() export interface __Options_Child { - ${dumpGetterSetter(GetSetDumper.BOTH, 'providevar', '(string | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providevar', '(IConsumeDecoratedVariable | undefined)', [dumpAnnotation('Watch', { value: 'ConsumeOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'providevar', '(string | undefined)', [dumpAnnotation('Consume', { alias: "" }), dumpAnnotation('Watch', { value: 'ConsumeOnChange' })])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_providevar', '(IConsumeDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_providevar', '(boolean | undefined)')} } @@ -372,7 +382,7 @@ function testWatchTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic watch transform', - [watchTransform, uiNoRecheck, recheck], + [watchTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testWatchTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts index d25c870a98ca5f779fbd23d315a2b7f6565bbe57..f073f762a210e8c0fe4a1b5ddc83efd8d41b1f79 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-griditem.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -49,13 +49,13 @@ import { GridAttribute as GridAttribute } from "arkui.component.grid"; import { GridItemAttribute as GridItemAttribute } from "arkui.component.gridItem"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; -import { Bindable as Bindable } from "arkui.component.common"; +import { makeBindable as makeBindable } from "arkui.component.common"; import { GridItemImpl as GridItemImpl } from "arkui.component.gridItem"; @@ -89,7 +89,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct MyStateSample extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_boo = STATE_MGMT_FACTORY.makeState(this, "boo", ((({let gensym___9142460 = initializers; (((gensym___9142460) == (null)) ? undefined : gensym___9142460.boo)})) ?? (true))); } @@ -106,39 +106,34 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_boo!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - GridImpl(@memo() ((instance: GridAttribute): void => { + }), @Memo() (() => { + GridImpl(@Memo() ((instance: GridAttribute): void => { instance.setGridOptions(undefined, undefined).applyAttributesFinish(); return; - }), @memo() (() => { - GridItemImpl(@memo() ((instance: GridItemAttribute): void => { - instance.setGridItemOptions(undefined).selected(({ - value: this.boo, - onChange: ((value: boolean) => { - this.boo = value; - }), - } as Bindable)).applyAttributesFinish(); + }), @Memo() (() => { + GridItemImpl(@Memo() ((instance: GridItemAttribute): void => { + instance.setGridItemOptions(undefined).selected(makeBindable(this.boo, ((value) => { + this.boo = value; + }))).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("nihao", undefined).applyAttributesFinish(); return; }), undefined); })); - GridItemImpl(@memo() ((instance: GridItemAttribute): void => { - instance.setGridItemOptions(undefined).selected(({ - value: c, - onChange: ((value: boolean) => { - c = value; - }), - } as Bindable)).applyAttributesFinish(); + GridItemImpl(@Memo() ((instance: GridItemAttribute): void => { + instance.setGridItemOptions(undefined).selected(makeBindable(c, ((value) => { + c = value; + }))).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("nihao", undefined).applyAttributesFinish(); return; }), undefined); @@ -148,11 +143,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); }), undefined, undefined, undefined); @@ -163,7 +162,7 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'boo', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'boo', '(boolean | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_boo', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_boo', '(boolean | undefined)')} @@ -176,7 +175,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test griditem bindable capability', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-textpicker.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-textpicker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d0bf8a5158c85b063eb527e0d8d408e346efa77 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-textpicker.test.ts @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; +import { parseDumpSrc } from '../../../utils/parse-string'; +import { uiNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { uiTransform } from '../../../../ui-plugins'; +import { Plugins } from '../../../../common/plugin-context'; + +const DOUBLE_DOLLAR_DIR_PATH: string = 'double-dollar'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, DOUBLE_DOLLAR_DIR_PATH, 'double-dollar-textpicker.ets'), +]; + +const pluginTester = new PluginTester('test Text and TextPicker bindable capability', buildConfig); + +const parsedTransform: Plugins = { + name: 'double-dollar-textpicker', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; + +import { ColumnImpl as ColumnImpl } from "arkui.component.column"; + +import { TextPickerAttribute as TextPickerAttribute } from "arkui.component.textPicker"; + +import { TextPickerImpl as TextPickerImpl } from "arkui.component.textPicker"; + +import { Memo as Memo } from "arkui.incremental.annotation"; + +import { TextInputAttribute as TextInputAttribute } from "arkui.component.textInput"; + +import { makeBindable as makeBindable } from "arkui.component.common"; + +import { TextInputImpl as TextInputImpl } from "arkui.component.textInput"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; + +import { Text as Text, Column as Column, Component as Component, TextInput as TextInput, $$ as $$, TextPicker as TextPicker, TextPickerOptions as TextPickerOptions } from "@ohos.arkui.component"; + +import { State as State } from "@ohos.arkui.stateManagement"; + +function main() {} + + +@Component() final struct MyStateSample extends CustomComponent { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { + this.__backing_tt = STATE_MGMT_FACTORY.makeState(this, "tt", ((({let gensym___111800258 = initializers; + (((gensym___111800258) == (null)) ? undefined : gensym___111800258.tt)})) ?? ("state var"))); + this.__backing_index = STATE_MGMT_FACTORY.makeState(this, "index", ((({let gensym___91647805 = initializers; + (((gensym___91647805) == (null)) ? undefined : gensym___91647805.index)})) ?? (1))); + this.__backing_select = STATE_MGMT_FACTORY.makeState(this, "select", ((({let gensym___90525328 = initializers; + (((gensym___90525328) == (null)) ? undefined : gensym___90525328.select)})) ?? (0))); + this.__backing_selectArr = STATE_MGMT_FACTORY.makeState>(this, "selectArr", ((({let gensym___264591166 = initializers; + (((gensym___264591166) == (null)) ? undefined : gensym___264591166.selectArr)})) ?? ([0, 1, 2]))); + this.__backing_fruits = ((({let gensym___19120252 = initializers; + (((gensym___19120252) == (null)) ? undefined : gensym___19120252.fruits)})) ?? (["apple1", "orange2", "peach3", "grape4"])); + } + + public __updateStruct(initializers: (__Options_MyStateSample | undefined)): void {} + + private __backing_tt?: IStateDecoratedVariable; + public get tt(): string { + return this.__backing_tt!.get(); + } + + public set tt(value: string) { + this.__backing_tt!.set(value); + } + + private __backing_index?: IStateDecoratedVariable; + public get index(): int { + return this.__backing_index!.get(); + } + + public set index(value: int) { + this.__backing_index!.set(value); + } + + private __backing_select?: IStateDecoratedVariable; + public get select(): int { + return this.__backing_select!.get(); + } + + public set select(value: int) { + this.__backing_select!.set(value); + } + + private __backing_selectArr?: IStateDecoratedVariable>; + public get selectArr(): Array { + return this.__backing_selectArr!.get(); + } + + public set selectArr(value: Array) { + this.__backing_selectArr!.set(value); + } + + private __backing_fruits?: Array; + public get fruits(): Array { + return (this.__backing_fruits as Array); + } + + public set fruits(value: Array) { + this.__backing_fruits = value; + } + + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { + instance.setColumnOptions(undefined).margin(10).applyAttributesFinish(); + return; + }), @Memo() (() => { + TextInputImpl(@Memo() ((instance: TextInputAttribute): void => { + instance.setTextInputOptions({ + text: makeBindable(this.tt, ((value) => { + this.tt = value; + })), + }).applyAttributesFinish(); + return; + }), undefined); + TextPickerImpl(@Memo() ((instance: TextPickerAttribute): void => { + instance.setTextPickerOptions(({ + range: this.fruits, + selected: makeBindable(this.select, ((value) => { + this.select = value; + })), + value: makeBindable(this.fruits[0], ((value) => { + this.fruits[0] = value; + })), + } as TextPickerOptions)).applyAttributesFinish(); + return; + }), undefined); + TextPickerImpl(@Memo() ((instance: TextPickerAttribute): void => { + instance.setTextPickerOptions(({ + range: this.fruits, + selected: makeBindable(this.selectArr, ((value) => { + this.selectArr = value; + })), + value: makeBindable(this.fruits, ((value) => { + this.fruits = value; + })), + } as TextPickerOptions)).applyAttributesFinish(); + return; + }), undefined); + TextPickerImpl(@Memo() ((instance: TextPickerAttribute): void => { + instance.setTextPickerOptions(({ + range: this.fruits, + selected: makeBindable(this.selectArr, ((value) => { + this.selectArr = value; + })), + value: makeBindable(this.fruits[this.index], ((value) => { + this.fruits[this.index] = value; + })), + } as TextPickerOptions)).applyAttributesFinish(); + return; + }), undefined); + })); + } + + public constructor() {} + +} + +@Component() export interface __Options_MyStateSample { + ${dumpGetterSetter(GetSetDumper.BOTH, 'tt', '(string | undefined)', [dumpAnnotation('State')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_tt', '(IStateDecoratedVariable | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_tt', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'index', '(int | undefined)', [dumpAnnotation('State')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_index', '(IStateDecoratedVariable | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_index', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'select', '(int | undefined)', [dumpAnnotation('State')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_select', '(IStateDecoratedVariable | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_select', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'selectArr', '(Array | undefined)', [dumpAnnotation('State')])} + ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_selectArr', '(IStateDecoratedVariable> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_selectArr', '(boolean | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'fruits', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_fruits', '(boolean | undefined)')} +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test Text and TextPicker bindable capability', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts index a017a56e53eeab93a517a2cabb8c84284abfae14..843c5abfbbffa62ee962a31a0b5b169ea512b542 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/double-dollar/double-dollar-toggle.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, beforeUINoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -42,7 +42,11 @@ const expectedScript: string = ` import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; import { IStateDecoratedVariable as IStateDecoratedVariable } from "arkui.stateManagement.decorator"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { ToggleAttribute as ToggleAttribute } from "arkui.component.toggle"; +import { makeBindable as makeBindable } from "arkui.component.common"; +import { ToggleImpl as ToggleImpl } from "arkui.component.toggle"; +import { ColumnImpl as ColumnImpl } from "arkui.component.column"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ToggleAttribute as ToggleAttribute } from "arkui.component.toggle"; import { Bindable as Bindable } from "arkui.component.common"; import { ToggleImpl as ToggleImpl } from "arkui.component.toggle"; @@ -65,7 +69,7 @@ class BooleanClass { } @Component() final struct MyStateSample extends CustomComponent { - public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_MyStateSample | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_boo = STATE_MGMT_FACTORY.makeState>(this, "boo", ((({let gensym___9142460 = initializers; (((gensym___9142460) == (null)) ? undefined : gensym___9142460.boo)})) ?? ([true, false, true]))); this.__backing_booClass = STATE_MGMT_FACTORY.makeState(this, "booClass", ((({let gensym___145381365 = initializers; @@ -94,44 +98,36 @@ class BooleanClass { this.__backing_booClass!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ToggleImpl(@memo() ((instance: ToggleAttribute): void => { + }), @Memo() (() => { + ToggleImpl(@Memo() ((instance: ToggleAttribute): void => { instance.setToggleOptions({ type: ToggleType.Checkbox, - isOn: ({ - value: this.boo[0], - onChange: ((value: boolean) => { - this.boo[0] = value; - }), - } as Bindable), + isOn: makeBindable(this.boo[0], ((value) => { + this.boo[0] = value; + })), }).applyAttributesFinish(); return; }), undefined); - ToggleImpl(@memo() ((instance: ToggleAttribute): void => { + ToggleImpl(@Memo() ((instance: ToggleAttribute): void => { instance.setToggleOptions({ type: ToggleType.Checkbox, - isOn: ({ - value: this.booClass.isOn, - onChange: ((value: boolean) => { - this.booClass.isOn = value; - }), - } as Bindable), + isOn: makeBindable(this.booClass.isOn, ((value) => { + this.booClass.isOn = value; + })), }).applyAttributesFinish(); return; }), undefined); - ToggleImpl(@memo() ((instance: ToggleAttribute): void => { + ToggleImpl(@Memo() ((instance: ToggleAttribute): void => { instance.setToggleOptions({ type: ToggleType.Checkbox, - isOn: ({ - value: c[1], - onChange: ((value: boolean) => { - c[1] = value; - }), - } as Bindable), + isOn: makeBindable(c[1], ((value) => { + c[1] = value; + })), }).applyAttributesFinish(); return; }), undefined); @@ -139,15 +135,18 @@ class BooleanClass { } public constructor() {} + + static { + } } @Component() export interface __Options_MyStateSample { - ${dumpGetterSetter(GetSetDumper.BOTH, 'boo', '(Array | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'boo', '(Array | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_boo', '(IStateDecoratedVariable> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_boo', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'booClass', '(BooleanClass | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'booClass', '(BooleanClass | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_booClass', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_booClass', '(boolean | undefined)')} @@ -160,7 +159,7 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test toggle bindable capability', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform, beforeUINoRecheck, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts index ceb3d879309bf366481182f0eaced8ee0a848177..57736cd2aff906e8d8d24dffa30ab10690274320 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/entry-only.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -85,11 +85,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry only', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts index 21a9dccbf9df97425614a52073b007d76cc6afc4..8c2b0b20c5f425d3c2c19681dc7a5440311709f8 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-false.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -89,11 +89,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with storage and useSharedStorage false', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts index a9eba9b08cdda159f44abdd0a93fec94ac8571cf..dbcd03417dceb43a4d584907b2690a18437c1a5a 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage-use-shared-storage-true.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -88,11 +88,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with storage and useSharedStorage true', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts index 8295b0d3f217a6181eedabe34ccb8384b361e07c..d576c82ffb054b57fe27512441757f8dc746cd1c 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/storage.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -90,11 +90,11 @@ function testEntryStorageTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with only storage', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryStorageTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts index abd0f84b92f698fc012f76f2ef921c56428cbcb4..437bcd2e83763d3aa3d77ec0094e7934be3d2714 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-false.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -89,11 +89,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with only useSharedStorage false', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts index 73a312212832a2690713eb8fae1348993a0c0432..9b191db058e22f1a738d1838ae558f150f39afe1 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/localstorage/use-shared-storage-true.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -90,11 +90,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with only useSharedStorage true', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts index f97072b99aa763779b8ddca1748824763efa962a..f4ca0e48cf81fc84608863def7edcb32cb9605c7 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name-storage-shared.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -90,11 +90,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with only routeName', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts index e04bfe92759cd5be2cbecc40e72f7d1a339665c1..a2653ce9ea3c86a3b839bfa17018f9ad0df75515 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/entry/route-name/route-name.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; import { parseDumpSrc } from '../../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -86,11 +86,11 @@ function testEntryTransformer(this: PluginTestContext): void { pluginTester.run( 'test entry with only routeName', - [parsedTransform, uiNoRecheck, recheck], + [parsedTransform], { 'parsed': [testEntryTransformer], }, { - stopAfter: 'parsed', + stopAfter: 'checked', } ); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/exports/struct-default-export.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/exports/struct-default-export.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..881c72a766f2f8e470a04a1d0280692f484ffbd1 --- /dev/null +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/exports/struct-default-export.test.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 path from 'path'; +import { PluginTester } from '../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; +import { parseDumpSrc } from '../../../utils/parse-string'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; +import { ignoreNewLines } from '../../../utils/simplify-dump'; +import { uiTransform } from '../../../../ui-plugins'; +import { Plugins } from '../../../../common/plugin-context'; + +const EXPORT_DIR_PATH: string = 'exports'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, EXPORT_DIR_PATH, 'struct-default-export.ets'), +]; + +const exportParsed: Plugins = { + name: 'export-parsed', + parsed: uiTransform().parsed, +}; + +const pluginTester = new PluginTester('test default export struct', buildConfig); + +const expectedParsedScript: string = ` +import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; +import { PageLifeCycle as PageLifeCycle } from \"arkui.component.customComponent\"; +import { EntryPoint as EntryPoint } from \"arkui.component.customComponent\"; +import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; +import { Component as Component, Entry as Entry } from \"@ohos.arkui.component\"; +@Entry() @Component() export default final struct A extends CustomComponent implements PageLifeCycle { + public build() {} + public constructor() {} +} + +class __EntryWrapper extends EntryPoint { + public entry(): void { + A(); + } + public constructor() {} +} + +__EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ + bundleName: \"com.example.mock\", + moduleName: \"entry\", + pagePath: \"../../../exports/struct-default-export\", + pageFullPath: \"test/demo/mock/exports/struct-default-export\", + integratedHsp: \"false\", +} as NavInterface)) + +@Entry() @Component() export interface __Options_A { +} +`; + +function testExportParsed(this: PluginTestContext): void { + expect(parseDumpSrc(this?.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedParsedScript)); +} + +pluginTester.run( + 'test default export struct', + [exportParsed], + { + parsed: [testExportParsed] + }, + { + stopAfter: 'checked', + } +); diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts index 93f1a14766bb3411e912cba8769d0e256c63d2ec..10b5398ec3448af56f04db509f41a9f7ecc0ca23 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/import-struct.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -67,7 +67,7 @@ import { SimpleStruct as SimpleStruct } from "./utils/simple-struct"; `; const expectedCheckedScript: string = ` -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -84,11 +84,12 @@ function main() {} @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} - @memo() public build() { + @Memo() + public build() { SimpleStruct._instantiateImpl(undefined, (() => { return new SimpleStruct(); }), undefined, undefined, undefined); @@ -100,8 +101,8 @@ function main() {} }, undefined, undefined); SimpleStruct._instantiateImpl(undefined, (() => { return new SimpleStruct(); - }), undefined, undefined, @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), undefined, undefined, @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("a", undefined).applyAttributesFinish(); return; }), undefined); @@ -109,7 +110,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -127,7 +131,7 @@ function testImportChecked(this: PluginTestContext): void { pluginTester.run( 'test import struct from another file', - [importParsed, uiNoRecheck, recheck], + [importParsed, beforeUINoRecheck, uiNoRecheck, recheck], { 'parsed:import-struct': [testImportParsed], 'checked:ui-no-recheck:import-struct': [testImportChecked], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts index 7bd53416d39bb81e9c761f890909016ef2d45f32..a9f05aa8f2cc30db2275526ae9709a70ac904e13 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/imports/kit-import.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { beforeUINoRecheck, recheck, uiNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper, ignoreNewLines } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -91,10 +91,10 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ @Entry() @Component() export interface __Options_A { ${ignoreNewLines(` - a?: string; + @State() a?: string; @State() __backing_a?: string; __options_has_a?: boolean; - b?: string; + @PropRef() b?: string; @PropRef() __backing_b?: string; __options_has_b?: boolean; `)} @@ -115,7 +115,7 @@ import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { ButtonAttribute as ButtonAttribute } from "arkui.component.button"; @@ -152,7 +152,7 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct A extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_A | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_A | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_a = STATE_MGMT_FACTORY.makeState(this, "a", ((({let gensym___94024326 = initializers; (((gensym___94024326) == (null)) ? undefined : gensym___94024326.a)})) ?? ("str"))); this.__backing_b = STATE_MGMT_FACTORY.makePropRef(this, "b", (initializers!.b as string)); @@ -185,16 +185,17 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ this.__backing_b!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + }), @Memo() (() => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("button", undefined).onClick(((e: ClickEvent) => {})).applyAttributesFinish(); return; }), undefined); - TextImpl(@memo() ((instance: TextAttribute): void => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions("text", undefined).fontSize(20).applyAttributesFinish(); return; }), undefined); @@ -202,11 +203,15 @@ __EntryWrapper.RegisterNamedRouter("", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { A._instantiateImpl(undefined, (() => { return new A(); }), undefined, undefined, undefined); @@ -217,11 +222,11 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() export interface __Options_A { - ${dumpGetterSetter(GetSetDumper.BOTH, 'a', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'a', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_a', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_a', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'b', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'b', '(string | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_b', '(IPropRefDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_b', '(boolean | undefined)')} @@ -238,7 +243,7 @@ function testImportChecked(this: PluginTestContext): void { pluginTester.run( 'test imports from different sources', - [importParsed, uiNoRecheck, recheck], + [importParsed, beforeUINoRecheck, uiNoRecheck, recheck], { parsed: [testImportParsed], 'checked:ui-no-recheck': [testImportChecked], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts index 4f3e6d36e46633c1dd8f538014781cddc7362bec..f8809169008bae83976c47370ced0eef69f6fc81 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/builder-in-generic.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -46,7 +46,7 @@ import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { NavInterface as NavInterface } from "arkui.component.customComponent"; @@ -55,17 +55,21 @@ import { EntryPoint as EntryPoint } from "arkui.component.customComponent"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; import { Builder as Builder, Text as Text, Color as Color, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Entry as Entry, Component as Component, Row as Row, ForEach as ForEach } from "@ohos.arkui.component"; import { State as State } from "@ohos.arkui.stateManagement"; -@memo() let globalBuilder: @Builder() ((value: string, size: number)=> void); +@Memo() let globalBuilder: @Builder() ((value: string, size: number)=> void); let builderArr: Array<@Builder() ((value: string, size: number)=> void)>; function main() {} -@memo() function MyBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function MyBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).applyAttributesFinish(); return; }), undefined); } -@memo() function YourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function YourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).fontColor(Color.Pink).applyAttributesFinish(); return; }), undefined); @@ -80,7 +84,7 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ integratedHsp: \"false\", } as NavInterface)); @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeState(this, \"message\", ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.message)})) ?? (\"Hello World\"))); } @@ -92,16 +96,17 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ public set message(value: string) { this.__backing_message!.set(value); } - @memo() public build() { - RowImpl(@memo() ((instance: RowAttribute): void => { + @Memo() + public build() { + RowImpl(@Memo() ((instance: RowAttribute): void => { instance.setRowOptions(undefined).height("100%").applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { globalBuilder(this.message, 50); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return builderArr; - }), @memo() ((item: @Builder() ((value: string, size: number)=> void)) => { + }), ((@Memo() item: @Builder() ((value: string, size: number)=> void)) => { item("Hello World", 30); }), undefined); return; @@ -109,10 +114,15 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ })); } public constructor() {} + + static { + + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); }), undefined, undefined, undefined); @@ -121,7 +131,7 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} } @@ -140,7 +150,7 @@ import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from \"arkui.component.text\"; import { TextImpl as TextImpl } from "arkui.component.text"; import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; @@ -149,16 +159,18 @@ import { EntryPoint as EntryPoint } from \"arkui.component.customComponent\"; import { CustomComponent as CustomComponent } from \"arkui.component.customComponent\"; import { Builder as Builder, Text as Text, Color as Color, WrappedBuilder as WrappedBuilder, wrapBuilder as wrapBuilder, Entry as Entry, Component as Component, Row as Row, ForEach as ForEach } from \"@ohos.arkui.component\"; import { State as State } from \"@ohos.arkui.stateManagement\"; -@memo() let globalBuilder: @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); +@Memo() let globalBuilder: @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); let builderArr: Array<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>; function main() {} -@memo() function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -176,13 +188,15 @@ function main() {} return; } } -@memo() function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -210,7 +224,7 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ integratedHsp: \"false\", } as NavInterface)); @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeState(this, \"message\", ((({let gensym___ = initializers; (((gensym___) == (null)) ? undefined : gensym___.message)})) ?? (\"Hello World\"))); } @@ -222,13 +236,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ public set message(value: string) { this.__backing_message!.set(value); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + (136716185)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + RowImpl(__memo_context, ((__memo_id) + (136716185)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -240,14 +255,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } globalBuilder(__memo_context, ((__memo_id) + (76711614)), this.message, 50); - ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -256,14 +271,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } __memo_parameter_instance.value.setForEachOptions((() => { return builderArr; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, @Memo() item: @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)) => { const __memo_scope = __memo_context.scope(((__memo_id) + (223657391)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); + __memo_parameter_item.value(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); { __memo_scope.recache(); return; @@ -285,10 +300,15 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } } public constructor() {} + + static { + + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public entry(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -306,7 +326,7 @@ class __EntryWrapper extends EntryPoint { } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} } @@ -318,7 +338,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test builder with generic builder type', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts index f04673966100c5e7f1deb3ae5f453c85558f0be0..7b574453a3c4b7957f67012287d9ce8cb353e8ed 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/init-with-builder.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -41,7 +41,7 @@ const expectedUIScript: string = ` import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; import { TextImpl as TextImpl } from "arkui.component.text"; import { CustomComponent as CustomComponent } from "arkui.component.customComponent"; @@ -51,8 +51,10 @@ let globalBuilder: WrappedBuilder; function main() {} -@memo() function myBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function myBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).applyAttributesFinish(); return; }), undefined); @@ -60,24 +62,28 @@ function main() {} globalBuilder = wrapBuilder(myBuilder); -@memo() type MyBuilderFuncType = @Builder() ((value: string, size: number)=> void); +@Memo() type MyBuilderFuncType = @Builder() ((value: string, size: number)=> void); @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { globalBuilder.builder("hello", 50); })); } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -99,7 +105,7 @@ import { ColumnImpl as ColumnImpl } from "arkui.component.column"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -113,13 +119,15 @@ let globalBuilder: WrappedBuilder; function main() {} -@memo() function myBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function myBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + (52041161)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (175145513)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (175145513)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (47330804)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -140,20 +148,21 @@ function main() {} globalBuilder = wrapBuilder(myBuilder); -@memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); +@Memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (172572715)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (213104625)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (213104625)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -165,7 +174,7 @@ globalBuilder = wrapBuilder(myBuilder); __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (211301233)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -184,7 +193,10 @@ globalBuilder = wrapBuilder(myBuilder); } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -198,7 +210,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test wrap builder init with @Builder function', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts index 06ebb51d142bfa411b9d774a5ca7751150fc39d5..0c71d232977eabe0056a130c16c97e1b141278e5 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-generic.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -46,7 +46,7 @@ import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from \"arkui.component.text\"; import { TextImpl as TextImpl } from "arkui.component.text"; import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; @@ -60,14 +60,18 @@ let builderArr: Array let wrappedBuilder1: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>; let wrappedBuilder2: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>; function main() {} -@memo() function MyBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function MyBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).applyAttributesFinish(); return; }), undefined); } -@memo() function YourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function YourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).fontColor(Color.Pink).applyAttributesFinish(); return; }), undefined); @@ -84,7 +88,7 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ integratedHsp: \"false\", } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeState(this, "message", ((({let gensym___117212394 = initializers; (((gensym___117212394) == (null)) ? undefined : gensym___117212394.message)})) ?? ("Hello World"))); } @@ -100,16 +104,17 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ this.__backing_message!.set(value); } - @memo() public build() { - RowImpl(@memo() ((instance: RowAttribute): void => { + @Memo() + public build() { + RowImpl(@Memo() ((instance: RowAttribute): void => { instance.setRowOptions(undefined).height("100%").applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { globalBuilder.builder(this.message, 50); - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return builderArr; - }), @memo() ((item: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>) => { + }), ((item: WrappedBuilder<@Builder() ((value: string, size: number)=> void)>) => { item.builder("Hello World", 30); }), undefined); return; @@ -118,10 +123,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(): void { + @Memo() + public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); }), undefined, undefined, undefined); @@ -129,7 +138,7 @@ class __EntryWrapper extends EntryPoint { public constructor() {} } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} @@ -149,7 +158,7 @@ import { ForEachAttribute as ForEachAttribute } from "arkui.component.forEach"; import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from \"arkui.stateManagement.runtime\"; +import { Memo as Memo } from \"arkui.incremental.annotation\"; import { TextAttribute as TextAttribute } from \"arkui.component.text\"; import { TextImpl as TextImpl } from "arkui.component.text"; import { NavInterface as NavInterface } from \"arkui.component.customComponent\"; @@ -163,13 +172,15 @@ let builderArr: Array void)>; let wrappedBuilder2: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>; function main() {} -@memo() function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -187,13 +198,15 @@ function main() {} return; } } -@memo() function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + ()), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + ()), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -223,7 +236,7 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ integratedHsp: \"false\", } as NavInterface)); @Entry({useSharedStorage:false,storage:"",routeName:""}) @Component() final struct Index extends CustomComponent implements PageLifeCycle { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_message = STATE_MGMT_FACTORY.makeState(this, "message", ((({let gensym___117212394 = initializers; (((gensym___117212394) == (null)) ? undefined : gensym___117212394.message)})) ?? ("Hello World"))); } @@ -239,13 +252,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ this.__backing_message!.set(value); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (135515930)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + (136716185)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + RowImpl(__memo_context, ((__memo_id) + (136716185)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -257,14 +271,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } globalBuilder.builder(__memo_context, ((__memo_id) + (76711614)), this.message, 50); - ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (213687742)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (192802443)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -273,14 +287,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } __memo_parameter_instance.value.setForEachOptions((() => { return builderArr; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { const __memo_scope = __memo_context.scope(((__memo_id) + (223657391)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (218979098)), "Hello World", 30); { __memo_scope.recache(); return; @@ -303,10 +317,14 @@ __EntryWrapper.RegisterNamedRouter(\"\", new __EntryWrapper(), ({ } public constructor() {} + + static { + } } class __EntryWrapper extends EntryPoint { - @memo() public entry(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { + @Memo() + public entry(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -323,7 +341,7 @@ class __EntryWrapper extends EntryPoint { public constructor() {} } @Entry({useSharedStorage:false,storage:\"\",routeName:\"\"}) @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'message', '(string | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_message', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_message', '(boolean | undefined)')} @@ -336,7 +354,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test wrap builder with generic builder type', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-struct.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-struct.test.ts index b583d07a98b21fedd95d1246c4ba04ea2c487cbb..b75658617efa66b8438700993e8e4487b04bf1fd 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-struct.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-struct.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; @@ -83,7 +83,7 @@ import { RowImpl as RowImpl } from "arkui.component.row"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; @@ -97,7 +97,9 @@ import { Local as Local, Param as Param, Provider as Provider, Once as Once, Con function main() {} -@memo() function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function MyBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + (93169018)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -109,7 +111,9 @@ function main() {} } } -@memo() function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function YourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + (258460786)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -123,7 +127,7 @@ function main() {} @ComponentV2() final struct Index2 extends CustomComponentV2 { - public __initializeStruct(initializers: (__Options_Index2 | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index2 | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_builderRegular = ((({let gensym___265903007 = initializers; (((gensym___265903007) == (null)) ? undefined : gensym___265903007.builderRegular)})) ?? (MyBuilder)); this.__backing_builderRegular2 = ((({let gensym___143278645 = initializers; @@ -318,13 +322,14 @@ function main() {} this.__backing_builderConsumer3!.set(value); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (75236795)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + (173773669)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + RowImpl(__memo_context, ((__memo_id) + (173773669)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (241913892)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -336,7 +341,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (262314519)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -344,7 +349,7 @@ function main() {} } this.builderRegular(__memo_context, ((__memo_id) + (137225318)), "Hello World", 50); this.builderRegular2.builder(__memo_context, ((__memo_id) + (211301233)), "Hello World", 50); - ForEachImpl(__memo_context, ((__memo_id) + (218979098)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (218979098)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -353,14 +358,14 @@ function main() {} } __memo_parameter_instance.value.setForEachOptions((() => { return this.builderRegular3; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { const __memo_scope = __memo_context.scope(((__memo_id) + (46726221)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (213104625)), "Hello World", 50); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (213104625)), "Hello World", 50); { __memo_scope.recache(); return; @@ -373,7 +378,7 @@ function main() {} })); this.builderProvider(__memo_context, ((__memo_id) + (223657391)), "Hello World", 50); this.builderProvider2.builder(__memo_context, ((__memo_id) + (192802443)), "Hello World", 50); - ForEachImpl(__memo_context, ((__memo_id) + (78055758)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (78055758)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (136716185)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -382,14 +387,14 @@ function main() {} } __memo_parameter_instance.value.setForEachOptions((() => { return this.builderProvider3; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { const __memo_scope = __memo_context.scope(((__memo_id) + (54078781)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (213687742)), "Hello World", 50); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (213687742)), "Hello World", 50); { __memo_scope.recache(); return; @@ -412,11 +417,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() final struct Index extends CustomComponent { - public __initializeStruct(initializers: (__Options_Index | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Index | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_builderRegular = ((({let gensym___133415523 = initializers; (((gensym___133415523) == (null)) ? undefined : gensym___133415523.builderRegular)})) ?? (MyBuilder)); this.__backing_builderRegular2 = ((({let gensym___182042467 = initializers; @@ -438,15 +446,15 @@ function main() {} if (({let gensym___14830560 = initializers; (((gensym___14830560) == (null)) ? undefined : gensym___14830560.__options_has_builderLink)})) { this.__backing_builderLink = STATE_MGMT_FACTORY.makeLink<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "builderLink", initializers!.__backing_builderLink!); - }; + } if (({let gensym___225609674 = initializers; (((gensym___225609674) == (null)) ? undefined : gensym___225609674.__options_has_builderLink2)})) { this.__backing_builderLink2 = STATE_MGMT_FACTORY.makeLink void)>>(this, "builderLink2", initializers!.__backing_builderLink2!); - }; + } if (({let gensym___44855388 = initializers; (((gensym___44855388) == (null)) ? undefined : gensym___44855388.__options_has_builderLink3)})) { this.__backing_builderLink3 = STATE_MGMT_FACTORY.makeLink void)>>>(this, "builderLink3", initializers!.__backing_builderLink3!); - }; + } this.__backing_builderProvide = STATE_MGMT_FACTORY.makeProvide<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "builderProvide", "builderProvide", ((({let gensym___142246099 = initializers; (((gensym___142246099) == (null)) ? undefined : gensym___142246099.builderProvide)})) ?? (MyBuilder)), false); this.__backing_builderProvide2 = STATE_MGMT_FACTORY.makeProvide void)>>(this, "builderProvide2", "builderProvide2", ((({let gensym___39863061 = initializers; @@ -456,18 +464,18 @@ function main() {} this.__backing_builderConsume = STATE_MGMT_FACTORY.makeConsume<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "builderConsume", "builderConsume"); this.__backing_builderConsume2 = STATE_MGMT_FACTORY.makeConsume void)>>(this, "builderConsume2", "builderConsume2"); this.__backing_builderConsume3 = STATE_MGMT_FACTORY.makeConsume void)>>>(this, "builderConsume3", "builderConsume3"); - this.__backing_builderStorageLink = STATE_MGMT_FACTORY.makeStorageLink<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderStorageLink", MyBuilder) - this.__backing_builderStorageLink2 = STATE_MGMT_FACTORY.makeStorageLink void)>>(this, "aa", "builderStorageLink2", wrapBuilder(MyBuilder)) - this.__backing_builderStorageLink3 = STATE_MGMT_FACTORY.makeStorageLink void)>>>(this, "aa", "builderStorageLink3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]) - this.__backing_builderStoragePropRef = STATE_MGMT_FACTORY.makeStoragePropRef<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderStoragePropRef", MyBuilder) - this.__backing_builderStoragePropRef2 = STATE_MGMT_FACTORY.makeStoragePropRef void)>>(this, "aa", "builderStoragePropRef2", wrapBuilder(MyBuilder)) - this.__backing_builderStoragePropRef3 = STATE_MGMT_FACTORY.makeStoragePropRef void)>>>(this, "aa", "builderStoragePropRef3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]) - this.__backing_builderLocalStorageLink = STATE_MGMT_FACTORY.makeLocalStorageLink<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderLocalStorageLink", MyBuilder) - this.__backing_builderLocalStorageLink2 = STATE_MGMT_FACTORY.makeLocalStorageLink void)>>(this, "aa", "builderLocalStorageLink2", wrapBuilder(MyBuilder)) - this.__backing_builderLocalStorageLink3 = STATE_MGMT_FACTORY.makeLocalStorageLink void)>>>(this, "aa", "builderLocalStorageLink3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]) - this.__backing_builderLocalStoragePropRef = STATE_MGMT_FACTORY.makeLocalStoragePropRef<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderLocalStoragePropRef", MyBuilder) - this.__backing_builderLocalStoragePropRef2 = STATE_MGMT_FACTORY.makeLocalStoragePropRef void)>>(this, "aa", "builderLocalStoragePropRef2", wrapBuilder(MyBuilder)) - this.__backing_builderLocalStoragePropRef3 = STATE_MGMT_FACTORY.makeLocalStoragePropRef void)>>>(this, "aa", "builderLocalStoragePropRef3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]) + this.__backing_builderStorageLink = STATE_MGMT_FACTORY.makeStorageLink<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderStorageLink", MyBuilder); + this.__backing_builderStorageLink2 = STATE_MGMT_FACTORY.makeStorageLink void)>>(this, "aa", "builderStorageLink2", wrapBuilder(MyBuilder)); + this.__backing_builderStorageLink3 = STATE_MGMT_FACTORY.makeStorageLink void)>>>(this, "aa", "builderStorageLink3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]); + this.__backing_builderStoragePropRef = STATE_MGMT_FACTORY.makeStoragePropRef<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderStoragePropRef", MyBuilder); + this.__backing_builderStoragePropRef2 = STATE_MGMT_FACTORY.makeStoragePropRef void)>>(this, "aa", "builderStoragePropRef2", wrapBuilder(MyBuilder)); + this.__backing_builderStoragePropRef3 = STATE_MGMT_FACTORY.makeStoragePropRef void)>>>(this, "aa", "builderStoragePropRef3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]); + this.__backing_builderLocalStorageLink = STATE_MGMT_FACTORY.makeLocalStorageLink<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderLocalStorageLink", MyBuilder); + this.__backing_builderLocalStorageLink2 = STATE_MGMT_FACTORY.makeLocalStorageLink void)>>(this, "aa", "builderLocalStorageLink2", wrapBuilder(MyBuilder)); + this.__backing_builderLocalStorageLink3 = STATE_MGMT_FACTORY.makeLocalStorageLink void)>>>(this, "aa", "builderLocalStorageLink3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]); + this.__backing_builderLocalStoragePropRef = STATE_MGMT_FACTORY.makeLocalStoragePropRef<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>(this, "aa", "builderLocalStoragePropRef", MyBuilder); + this.__backing_builderLocalStoragePropRef2 = STATE_MGMT_FACTORY.makeLocalStoragePropRef void)>>(this, "aa", "builderLocalStoragePropRef2", wrapBuilder(MyBuilder)); + this.__backing_builderLocalStoragePropRef3 = STATE_MGMT_FACTORY.makeLocalStoragePropRef void)>>>(this, "aa", "builderLocalStoragePropRef3", [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)]); } public __updateStruct(initializers: (__Options_Index | undefined)): void { @@ -755,13 +763,14 @@ function main() {} this.__backing_builderLocalStoragePropRef3!.set(value); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (187581126)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - RowImpl(__memo_context, ((__memo_id) + (136286509)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { + RowImpl(__memo_context, ((__memo_id) + (136286509)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: RowAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (151409217)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -773,7 +782,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (225484108)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -781,7 +790,7 @@ function main() {} } this.builderRegular(__memo_context, ((__memo_id) + (238360624)), "Hello World", 50); this.builderRegular2.builder(__memo_context, ((__memo_id) + (234157464)), "Hello World", 50); - ForEachImpl(__memo_context, ((__memo_id) + (72614054)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (72614054)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (204012763)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -790,14 +799,14 @@ function main() {} } __memo_parameter_instance.value.setForEachOptions((() => { return this.builderRegular3; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { const __memo_scope = __memo_context.scope(((__memo_id) + (18973066)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (75321118)), "Hello World", 50); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (75321118)), "Hello World", 50); { __memo_scope.recache(); return; @@ -810,7 +819,7 @@ function main() {} })); this.builderLocalStorageLink(__memo_context, ((__memo_id) + (172290133)), "Hello World", 50); this.builderLocalStorageLink2.builder(__memo_context, ((__memo_id) + (5605714)), "Hello World", 50); - ForEachImpl(__memo_context, ((__memo_id) + (157355641)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (157355641)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (27183850)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -819,14 +828,14 @@ function main() {} } __memo_parameter_instance.value.setForEachOptions((() => { return this.builderLocalStorageLink3; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)>) => { const __memo_scope = __memo_context.scope(((__memo_id) + (139295044)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (257873411)), "Hello World", 50); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (257873411)), "Hello World", 50); { __memo_scope.recache(); return; @@ -849,194 +858,196 @@ function main() {} } public constructor() {} + + static { + } } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} @ComponentV2() export interface __Options_Index2 { - ${dumpGetterSetter(GetSetDumper.GET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'builderRegular2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular2', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'builderRegular3', '(Array void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderLocal', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderLocal', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocal', '(ILocalDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocal', '(ILocalDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderLocal', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Local'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderLocal', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Local')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocal', '(ILocalDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocal', '(ILocalDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocal', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocal2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocal2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocal2', '(ILocalDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocal2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocal3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocal3', '(Array void)>> | undefined)', [dumpAnnotation('Local')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocal3', '(ILocalDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocal3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderParam', '(IParamDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderParam', '(IParamDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Param')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderParam', '(IParamDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderParam', '(IParamDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderParam', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderParam2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderParam2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderParam2', '(IParamDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderParam2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderParam3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderParam3', '(Array void)>> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderParam3', '(IParamDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderParam3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderOnceParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderOnceParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderOnceParam', '(IParamOnceDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param'), dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderOnceParam', '(IParamOnceDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param')], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderOnceParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderOnceParam', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderOnceParam', '(IParamOnceDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderOnceParam', '(IParamOnceDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param')], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderOnceParam', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderOnceParam2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderOnceParam2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderOnceParam2', '(IParamOnceDecoratedVariable void)>> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderOnceParam2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderOnceParam3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderOnceParam3', '(Array void)>> | undefined)', [dumpAnnotation('Param'), dumpAnnotation('Once')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderOnceParam3', '(IParamOnceDecoratedVariable void)>>> | undefined)', [dumpAnnotation('Param')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderOnceParam3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderProvider', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderProvider', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderProvider', '(IProviderDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderProvider', '(IProviderDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderProvider', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Provider', { alias: "" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderProvider', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Provider', { alias: "" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderProvider', '(IProviderDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderProvider', '(IProviderDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvider', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvider2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvider2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderProvider2', '(IProviderDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvider2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvider3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvider3', '(Array void)>> | undefined)', [dumpAnnotation('Provider', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderProvider3', '(IProviderDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvider3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderConsumer', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderConsumer', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderConsumer', '(IConsumerDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderConsumer', '(IConsumerDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderConsumer', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Consumer', { alias: "" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderConsumer', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Consumer', { alias: "" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderConsumer', '(IConsumerDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderConsumer', '(IConsumerDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsumer', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsumer2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsumer2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderConsumer2', '(IConsumerDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsumer2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsumer3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsumer3', '(Array void)>> | undefined)', [dumpAnnotation('Consumer', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderConsumer3', '(IConsumerDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsumer3', '(boolean | undefined)')} } @Component() export interface __Options_Index { - ${dumpGetterSetter(GetSetDumper.GET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderRegular', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'builderRegular2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular2', '(boolean | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, 'builderRegular3', '(Array void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderRegular3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderState', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderState', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderState', '(IStateDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderState', '(IStateDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderState', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('State'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderState', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('State')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderState', '(IStateDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderState', '(IStateDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderState', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderState2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderState2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderState2', '(IStateDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderState2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderState3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderState3', '(Array void)>> | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderState3', '(IStateDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderState3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderPropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderPropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderPropRef', '(IPropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderPropRef', '(IPropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderPropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('PropRef'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderPropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('PropRef')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderPropRef', '(IPropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderPropRef', '(IPropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderPropRef', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderPropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderPropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderPropRef2', '(IPropRefDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderPropRef2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderPropRef3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderPropRef3', '(Array void)>> | undefined)', [dumpAnnotation('PropRef')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderPropRef3', '(IPropRefDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderPropRef3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('__Link_intrinsic'), dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('__Link_intrinsic')], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLink', '(LinkSourceType<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLink', '(LinkSourceType<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Link'), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Link')], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLink', '(LinkSourceType<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLink', '(LinkSourceType<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLink', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLink2', '(LinkSourceType void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLink2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLink3', '(Array void)>> | undefined)', [dumpAnnotation('__Link_intrinsic')])} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLink3', '(Array void)>> | undefined)', [dumpAnnotation('Link')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLink3', '(LinkSourceType void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLink3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderProvide', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderProvide', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderProvide', '(IProvideDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderProvide', '(IProvideDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderProvide', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Provide', { alias: "builderProvide", allowOverride: false }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderProvide', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Provide', { alias: "builderProvide", allowOverride: false })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderProvide', '(IProvideDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderProvide', '(IProvideDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvide', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvide2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvide2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Provide', { alias: "builderProvide2", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderProvide2', '(IProvideDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvide2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvide3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderProvide3', '(Array void)>> | undefined)', [dumpAnnotation('Provide', { alias: "builderProvide3", allowOverride: false })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderProvide3', '(IProvideDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderProvide3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderConsume', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderConsume', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderConsume', '(IConsumeDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderConsume', '(IConsumeDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderConsume', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Consume', { alias: "" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderConsume', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('Consume', { alias: "" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderConsume', '(IConsumeDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderConsume', '(IConsumeDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsume', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsume2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsume2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderConsume2', '(IConsumeDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsume2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsume3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderConsume3', '(Array void)>> | undefined)', [dumpAnnotation('Consume', { alias: "" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderConsume3', '(IConsumeDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderConsume3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderStorageLink', '(IStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderStorageLink', '(IStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('StorageLink', { value: "aa" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('StorageLink', { value: "aa" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderStorageLink', '(IStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderStorageLink', '(IStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStorageLink', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStorageLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStorageLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('StorageLink', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderStorageLink2', '(IStorageLinkDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStorageLink2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStorageLink3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStorageLink3', '(Array void)>> | undefined)', [dumpAnnotation('StorageLink', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderStorageLink3', '(IStorageLinkDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStorageLink3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderStoragePropRef', '(IStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderStoragePropRef', '(IStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('StoragePropRef', { value: "aa" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('StoragePropRef', { value: "aa" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderStoragePropRef', '(IStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderStoragePropRef', '(IStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStoragePropRef', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStoragePropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStoragePropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('StoragePropRef', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderStoragePropRef2', '(IStoragePropRefDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStoragePropRef2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStoragePropRef3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderStoragePropRef3', '(Array void)>> | undefined)', [dumpAnnotation('StoragePropRef', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderStoragePropRef3', '(IStoragePropRefDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderStoragePropRef3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderLocalStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderLocalStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocalStorageLink', '(ILocalStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocalStorageLink', '(ILocalStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderLocalStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('LocalStorageLink', { value: "aa" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderLocalStorageLink', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('LocalStorageLink', { value: "aa" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocalStorageLink', '(ILocalStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocalStorageLink', '(ILocalStorageLinkDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStorageLink', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStorageLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStorageLink2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('LocalStorageLink', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocalStorageLink2', '(ILocalStorageLinkDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStorageLink2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStorageLink3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStorageLink3', '(Array void)>> | undefined)', [dumpAnnotation('LocalStorageLink', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocalStorageLink3', '(ILocalStorageLinkDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStorageLink3', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.GET, 'builderLocalStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, 'builderLocalStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [], [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocalStoragePropRef', '(ILocalStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('memo')])} - ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocalStoragePropRef', '(ILocalStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('memo')])} + ${dumpGetterSetter(GetSetDumper.GET, 'builderLocalStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "aa" }), dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, 'builderLocalStoragePropRef', '(@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void) | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "aa" })], [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.GET, '__backing_builderLocalStoragePropRef', '(ILocalStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('Memo')])} + ${dumpGetterSetter(GetSetDumper.SET, '__backing_builderLocalStoragePropRef', '(ILocalStoragePropRefDecoratedVariable<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [], [dumpAnnotation('Memo')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStoragePropRef', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStoragePropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStoragePropRef2', '(WrappedBuilder<@Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void)> | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocalStoragePropRef2', '(ILocalStoragePropRefDecoratedVariable void)>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStoragePropRef2', '(boolean | undefined)')} - ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStoragePropRef3', '(Array void)>> | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'builderLocalStoragePropRef3', '(Array void)>> | undefined)', [dumpAnnotation('LocalStoragePropRef', { value: "aa" })])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_builderLocalStoragePropRef3', '(ILocalStoragePropRefDecoratedVariable void)>>> | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_builderLocalStoragePropRef3', '(boolean | undefined)')} } @@ -1048,7 +1059,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test wrap builder in struct property', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts index a744e1f679674f1f1c1fc4112768f3d4a1574dd5..f538352b4c690074e6bb2e9ad694b9a1cdde37fe 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-in-ui.test.ts @@ -18,7 +18,7 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -48,7 +48,7 @@ import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -63,49 +63,58 @@ const globalBuilderArr: Array> = [wrapBuilder( function main() {} -@memo() function myBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function myBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).applyAttributesFinish(); return; }), undefined); } -@memo() function yourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { - TextImpl(@memo() ((instance: TextAttribute): void => { +@Builder() +@Memo() +function yourBuilder(@MemoSkip() value: string, @MemoSkip() size: number) { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(value, undefined).fontSize(size).applyAttributesFinish(); return; }), undefined); } -@memo() type MyBuilderFuncType = @Builder() ((value: string, size: number)=> void); +@Memo() type MyBuilderFuncType = @Builder() ((value: string, size: number)=> void); @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: ((()=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: ((()=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} - @memo() public testBuilder() { - ForEachImpl(@memo() ((instance: ForEachAttribute): void => { + @Memo() + public testBuilder() { + ForEachImpl(@Memo() ((instance: ForEachAttribute): void => { instance.setForEachOptions((() => { return globalBuilderArr; - }), @memo() ((item: WrappedBuilder) => { + }), ((item: WrappedBuilder) => { item.builder("hello world", 39); }), undefined); return; })); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { this.testBuilder(); })); } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -130,7 +139,7 @@ import { ForEachImpl as ForEachImpl } from "arkui.component.forEach"; import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -145,13 +154,15 @@ const globalBuilderArr: Array> = [wrapBuilder( function main() {} -@memo() function myBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function myBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + (52041161)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (175145513)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (175145513)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (47330804)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -170,13 +181,15 @@ function main() {} } } -@memo() function yourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { +@Builder() +@Memo() +function yourBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() value: string, @MemoSkip() size: number) { const __memo_scope = __memo_context.scope(((__memo_id) + (151467670)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (211301233)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (211301233)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (137225318)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -195,20 +208,21 @@ function main() {} } } -@memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); +@Memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, value: string, size: number)=> void); @Component() final struct ImportStruct extends CustomComponent { - public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} + public __initializeStruct(initializers: (__Options_ImportStruct | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void {} public __updateStruct(initializers: (__Options_ImportStruct | undefined)): void {} - @memo() public testBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public testBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (102938669)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ForEachImpl(__memo_context, ((__memo_id) + (223657391)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { + ForEachImpl(__memo_context, ((__memo_id) + (223657391)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ForEachAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (218979098)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -217,14 +231,14 @@ function main() {} } __memo_parameter_instance.value.setForEachOptions((() => { return globalBuilderArr; - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder) => { + }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, item: WrappedBuilder) => { const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 1); const __memo_parameter_item = __memo_scope.param(0, item); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - item.builder(__memo_context, ((__memo_id) + (46726221)), "hello world", 39); + __memo_parameter_item.value.builder(__memo_context, ((__memo_id) + (46726221)), "hello world", 39); { __memo_scope.recache(); return; @@ -241,13 +255,14 @@ function main() {} } } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (245938697)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (78055758)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (78055758)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (213687742)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -259,7 +274,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (136716185)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -278,7 +293,10 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_ImportStruct { @@ -292,7 +310,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test wrap builder in UI', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts index 844e6148b82f4cf6919166379b23e37c44cc0fc5..0750614dbb2dd10499f4018093ddfc76071ca401 100644 --- a/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts +++ b/ui2abc/arkui-plugins/test/ut/ui-plugins/wrap-builder/wrap-builder-with-lambda.test.ts @@ -18,9 +18,9 @@ import { PluginTester } from '../../../utils/plugin-tester'; import { mockBuildConfig } from '../../../utils/artkts-config'; import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; import { parseDumpSrc } from '../../../utils/parse-string'; -import { uiNoRecheck, recheck, memoNoRecheck } from '../../../utils/plugins'; +import { uiNoRecheck, recheck, memoNoRecheck, collectNoRecheck } from '../../../utils/plugins'; import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; -import { dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; +import { dumpAnnotation, dumpGetterSetter, GetSetDumper } from '../../../utils/simplify-dump'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -64,7 +64,7 @@ import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -85,12 +85,14 @@ const wBuilder: WrappedBuilder = wrapBuilder(overBuilder); function main() {} -@memo() function overBuilder(@MemoSkip() param: (()=> Tmp)) { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { +@Builder() +@Memo() +function overBuilder(@MemoSkip() param: (()=> Tmp)) { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { - TextImpl(@memo() ((instance: TextAttribute): void => { + }), @Memo() (() => { + TextImpl(@Memo() ((instance: TextAttribute): void => { instance.setTextOptions(\`wrapBuildervalue:\${param().paramA2}\`, undefined).applyAttributesFinish(); return; }), undefined); @@ -128,8 +130,6 @@ function main() {} @JSONRename({newName:"paramA2"}) private __backing_paramA2: string = "hello"; - public constructor() {} - public get paramA2(): string { this.conditionalAddRef(this.__meta); return this.__backing_paramA2; @@ -143,12 +143,17 @@ function main() {} } } + public constructor() {} + + static { + + } } -@memo() type MyBuilderFuncType = @Builder() ((param: (()=> Tmp))=> void); +@Memo() type MyBuilderFuncType = @Builder() ((param: (()=> Tmp))=> void); @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: ((()=> void) | undefined)): void { this.__backing_label = STATE_MGMT_FACTORY.makeState(this, "label", ((({let gensym___171896504 = initializers; (((gensym___171896504) == (null)) ? undefined : gensym___171896504.label)})) ?? (new Tmp()))); } @@ -165,17 +170,18 @@ function main() {} this.__backing_label!.set(value); } - @memo() public build() { - ColumnImpl(@memo() ((instance: ColumnAttribute): void => { + @Memo() + public build() { + ColumnImpl(@Memo() ((instance: ColumnAttribute): void => { instance.setColumnOptions(undefined).applyAttributesFinish(); return; - }), @memo() (() => { + }), @Memo() (() => { wBuilder.builder((() => { return { paramA2: this.label.paramA2, }; })); - ButtonImpl(@memo() ((instance: ButtonAttribute): void => { + ButtonImpl(@Memo() ((instance: ButtonAttribute): void => { instance.setButtonOptions("Click me", undefined).onClick(((e: ClickEvent) => { this.label.paramA2 = "ArkUI"; })).applyAttributesFinish(); @@ -185,11 +191,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'label', '(Tmp | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'label', '(Tmp | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_label', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_label', '(boolean | undefined)')} @@ -228,7 +237,7 @@ import { MemoSkip as MemoSkip } from "arkui.incremental.annotation"; import { ColumnAttribute as ColumnAttribute } from "arkui.component.column"; -import { memo as memo } from "arkui.stateManagement.runtime"; +import { Memo as Memo } from "arkui.incremental.annotation"; import { TextAttribute as TextAttribute } from "arkui.component.text"; @@ -249,13 +258,15 @@ const wBuilder: WrappedBuilder = wrapBuilder(overBuilder); function main() {} -@memo() function overBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() param: (()=> Tmp)) { +@Builder() +@Memo() +function overBuilder(__memo_context: __memo_context_type, __memo_id: __memo_id_type, @MemoSkip() param: (()=> Tmp)) { const __memo_scope = __memo_context.scope(((__memo_id) + (133793681)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (241913892)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (241913892)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -267,13 +278,13 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (175145513)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - TextImpl(__memo_context, ((__memo_id) + (47330804)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { + TextImpl(__memo_context, ((__memo_id) + (47330804)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: TextAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -328,8 +339,6 @@ function main() {} @JSONRename({newName:"paramA2"}) private __backing_paramA2: string = "hello"; - public constructor() {} - public get paramA2(): string { this.conditionalAddRef(this.__meta); return this.__backing_paramA2; @@ -343,12 +352,17 @@ function main() {} } } + public constructor() {} + + static { + + } } -@memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, param: (()=> Tmp))=> void); +@Memo() type MyBuilderFuncType = @Builder() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, param: (()=> Tmp))=> void); @Component() final struct Parent extends CustomComponent { - public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { + public __initializeStruct(initializers: (__Options_Parent | undefined), @Memo() content: (((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined)): void { this.__backing_label = STATE_MGMT_FACTORY.makeState(this, "label", ((({let gensym___171896504 = initializers; (((gensym___171896504) == (null)) ? undefined : gensym___171896504.label)})) ?? (new Tmp()))); } @@ -365,13 +379,14 @@ function main() {} this.__backing_label!.set(value); } - @memo() public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { + @Memo() + public build(__memo_context: __memo_context_type, __memo_id: __memo_id_type) { const __memo_scope = __memo_context.scope(((__memo_id) + (69406103)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; return; } - ColumnImpl(__memo_context, ((__memo_id) + (218979098)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { + ColumnImpl(__memo_context, ((__memo_id) + (218979098)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ColumnAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -383,7 +398,7 @@ function main() {} __memo_scope.recache(); return; } - }), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { + }), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { const __memo_scope = __memo_context.scope(((__memo_id) + (76711614)), 0); if (__memo_scope.unchanged) { __memo_scope.cached; @@ -394,7 +409,7 @@ function main() {} paramA2: this.label.paramA2, }; })); - ButtonImpl(__memo_context, ((__memo_id) + (46726221)), @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ButtonAttribute): void => { + ButtonImpl(__memo_context, ((__memo_id) + (46726221)), @Memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: ButtonAttribute): void => { const __memo_scope = __memo_context.scope(((__memo_id) + (213104625)), 1); const __memo_parameter_instance = __memo_scope.param(0, instance); if (__memo_scope.unchanged) { @@ -421,11 +436,14 @@ function main() {} } public constructor() {} + + static { + } } @Component() export interface __Options_Parent { - ${dumpGetterSetter(GetSetDumper.BOTH, 'label', '(Tmp | undefined)')} + ${dumpGetterSetter(GetSetDumper.BOTH, 'label', '(Tmp | undefined)', [dumpAnnotation('State')])} ${dumpGetterSetter(GetSetDumper.BOTH, '__backing_label', '(IStateDecoratedVariable | undefined)')} ${dumpGetterSetter(GetSetDumper.BOTH, '__options_has_label', '(boolean | undefined)')} @@ -438,7 +456,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'test wrap builder with lambda', - [parsedTransform, uiNoRecheck, memoNoRecheck, recheck], + [parsedTransform, collectNoRecheck, uiNoRecheck, memoNoRecheck, recheck], { 'checked:ui-no-recheck': [testUITransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/ui2abc/arkui-plugins/test/utils/artkts-config.ts b/ui2abc/arkui-plugins/test/utils/artkts-config.ts index 1bd1fabfeb188b3d9e6c447b41ba7e4e3d08cea3..ae9340941ff0b4bff587bdb52bf7d76d019e8d77 100644 --- a/ui2abc/arkui-plugins/test/utils/artkts-config.ts +++ b/ui2abc/arkui-plugins/test/utils/artkts-config.ts @@ -40,7 +40,7 @@ import { } from './path-config'; import { ArkTSConfigContextCache } from './cache'; import { BuildConfig, CompileFileInfo, DependentModule } from './shared-types'; -import { initializeLibarkts } from './global'; +import { initializeLibarkts, TestGlobal } from './global'; import { ProjectConfig } from '../../common/plugin-context'; export interface ArkTSConfigObject { @@ -156,12 +156,6 @@ function traverseSDK(currentDir: string, pathSection: Record, } } -type TestGlobal = typeof globalThis & { - PANDA_SDK_PATH: string; - API_PATH: string; - KIT_PATH: string; -} - function mockBuildConfig(): BuildConfig { return { packageName: 'mock', diff --git a/ui2abc/arkui-plugins/test/utils/compile.ts b/ui2abc/arkui-plugins/test/utils/compile.ts index e2fedb08d01c368024639a055cf1cc6fb1a17c34..fff8a45a9735449bc6ed06c7c80b6f8edefe71d9 100644 --- a/ui2abc/arkui-plugins/test/utils/compile.ts +++ b/ui2abc/arkui-plugins/test/utils/compile.ts @@ -33,7 +33,7 @@ import { import { PluginDriver } from './plugin-driver'; import { PluginState, PluginContext, PluginExecutor } from '../../common/plugin-context'; import { concatObject } from './serializable'; -import { NodeCache } from '../../common/node-cache'; +import { NodeCacheFactory } from '../../common/node-cache'; function insertPlugin(driver: PluginDriver, plugin: PluginExecutor | undefined): boolean { const pluginContext: PluginContext = driver.getPluginContext(); @@ -300,14 +300,14 @@ function compileExternalProgram(emitter: EventEmitter, jobInfo: Jo function proceedToState(state: arkts.Es2pandaContextState, context: arkts.KNativePointer, forceDtsEmit = false): void { console.log('[TS WRAPPER] PROCEED TO STATE: ', arkts.getEnumName(arkts.Es2pandaContextState, state)); if (arkts.arktsGlobal.es2panda._ContextState(context) === arkts.Es2pandaContextState.ES2PANDA_STATE_ERROR) { - NodeCache.getInstance().clear(); + NodeCacheFactory.getInstance().clear(); processErrorState(state, context, forceDtsEmit); } if (state <= arkts.arktsGlobal.es2panda._ContextState(context)) { console.log('[TS WRAPPER] PROCEED TO STATE: SKIPPING'); return; } - NodeCache.getInstance().clear(); + NodeCacheFactory.getInstance().clear(); arkts.arktsGlobal.es2panda._ProceedToState(context, state); processErrorState(state, context, forceDtsEmit); } diff --git a/ui2abc/arkui-plugins/test/utils/global.ts b/ui2abc/arkui-plugins/test/utils/global.ts index bf74601d95643278ceaad7d56ad76c9e21bf41d8..1c3b6161fc0ec5f6e33838251684e77162d795d0 100644 --- a/ui2abc/arkui-plugins/test/utils/global.ts +++ b/ui2abc/arkui-plugins/test/utils/global.ts @@ -41,7 +41,7 @@ function createGlobalConfig( config.push(fileInfo.filePath); if (isUseCache) { - arkts.MemInitialize(); + arkts.memInitialize(); } arkts.arktsGlobal.filePath = fileInfo.filePath; return resetConfig(config); @@ -50,7 +50,7 @@ function createGlobalConfig( function destroyGlobalConfig(config: arkts.Config, isUseCache: boolean = true): void { destroyConfig(config.peer); if (isUseCache) { - arkts.arktsGlobal.es2panda._MemFinalize(); + arkts.memFinalize(); } } @@ -121,6 +121,16 @@ function initializeLibarkts(pandaSdkPath: string): void { arkts.initVisitsTable(); } +export type TestGlobal = typeof globalThis & { + PANDA_SDK_PATH: string; + API_PATH: string; + KIT_PATH: string; + UI_CACHE_ENABLED: boolean; + UI_UPDATE_ENABLED: boolean; + MEMO_CACHE_ENABLED: boolean; + MEMO_UPDATE_ENABLED: boolean; +}; + export { createGlobalConfig, destroyGlobalConfig, diff --git a/ui2abc/arkui-plugins/test/utils/parse-string.ts b/ui2abc/arkui-plugins/test/utils/parse-string.ts index 69430d5a74605e0e1361ee40c49b84df1ee9761d..81e796b982fb977a1cd77de68d619035d67e55a8 100644 --- a/ui2abc/arkui-plugins/test/utils/parse-string.ts +++ b/ui2abc/arkui-plugins/test/utils/parse-string.ts @@ -16,6 +16,7 @@ function parseDumpSrc(str: string): string { let _str: string = str; _str = cleanCopyRight(_str); + _str = removeImportStatements(_str); _str = removeSpaceAndReturn(_str); _str = replaceWithRandomNumber(_str); _str = organizeImports(_str); @@ -48,6 +49,14 @@ function removeSpaceAndReturn(str: string): string { return str.replace(spaceAndReturnRegex, '').trim(); } +/** + * @deprecated + */ +function removeImportStatements(str: string): string { + const importRegex = /^import\s+(?:(?:\*\s+as\s+\w+)|(?:\{[^}]*\})|(?:\w+(?:\s*,\s*\w+)*)|(?:\w+\s*,\s*\{[^}]*\})|\w+)?\s+from\s+['"`][^'"`]+['"`]\s*;?\s*$/gm; + return str.replace(importRegex, '').trim(); +} + function replaceWithRandomNumber(text: string): string { return text .replace(/(?<=__memo_id[\)+]?\s?\+\s?[\(+]?)\d+/g, () => '') diff --git a/ui2abc/arkui-plugins/test/utils/plugins/before-memo-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/before-memo-no-recheck.ts index 42ed5da55cffb1a1e22fe2b8c828db7ffe3ff7c6..5baf7996612e93ebff8a336815f34c0f81c333d9 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/before-memo-no-recheck.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/before-memo-no-recheck.ts @@ -16,8 +16,10 @@ import * as arkts from '@koalaui/libarkts'; import { PluginContext, Plugins } from '../../../common/plugin-context'; import { ProgramVisitor } from '../../../common/program-visitor'; -import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../../../common/predefines'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, NodeCacheNames } from '../../../common/predefines'; import { MemoVisitor } from '../../../collectors/memo-collectors/memo-visitor'; +import { NodeCacheFactory } from '../../../common/node-cache'; +import { TestGlobal } from '../global'; /** * AfterCheck before-memo-visit and cache any node that should be unmemoized with no recheck AST. @@ -27,14 +29,15 @@ export const beforeMemoNoRecheck: Plugins = { checked(this: PluginContext): arkts.ETSModule | undefined { let script: arkts.ETSModule | undefined; const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; - if (!!contextPtr) { + if ((global as TestGlobal).MEMO_CACHE_ENABLED && !!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.ast as arkts.ETSModule; - const builderLambdaTransformer = new MemoVisitor(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldCollectUpdate((global as TestGlobal).MEMO_UPDATE_ENABLED); + const memoVisitor = new MemoVisitor(); const programVisitor = new ProgramVisitor({ pluginName: beforeMemoNoRecheck.name, state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, - visitors: [builderLambdaTransformer], + visitors: [memoVisitor], skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, pluginContext: this, }); diff --git a/ui2abc/arkui-plugins/test/utils/plugins/before-ui-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/before-ui-no-recheck.ts new file mode 100644 index 0000000000000000000000000000000000000000..15932bd9e231ba81fb000d0122a32e3c9ba71413 --- /dev/null +++ b/ui2abc/arkui-plugins/test/utils/plugins/before-ui-no-recheck.ts @@ -0,0 +1,50 @@ +/* + * 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 { PluginContext, Plugins } from '../../../common/plugin-context'; +import { ProgramVisitor } from '../../../common/program-visitor'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, NodeCacheNames } from '../../../common/predefines'; +import { UIVisitor } from '../../../collectors/ui-collectors/ui-visitor'; +import { NodeCacheFactory } from '../../../common/node-cache'; +import { TestGlobal } from '../global'; + +/** + * AfterCheck before-ui-visit and cache any node that should be ui-transformed with no recheck AST. + */ +export const beforeUINoRecheck: Plugins = { + name: 'before-ui-no-recheck', + checked(this: PluginContext): arkts.ETSModule | undefined { + let script: arkts.ETSModule | undefined; + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if ((global as TestGlobal).UI_CACHE_ENABLED && !!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + script = program.ast as arkts.ETSModule; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).shouldCollectUpdate((global as TestGlobal).UI_UPDATE_ENABLED); + const uiVisitor = new UIVisitor(); + const programVisitor = new ProgramVisitor({ + pluginName: beforeUINoRecheck.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [uiVisitor], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: this, + }); + program = programVisitor.programVisitor(program); + script = program.ast as arkts.ETSModule; + return script; + } + return script; + }, +}; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts index 61c7f89f09d1961bcfb30cdc2a2cf5525f69eef3..8fc35a5e6047a8e921e0db4d3b93f3bb2a66fcb4 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts @@ -21,6 +21,7 @@ import { BuilderLambdaTransformer } from '../../../ui-plugins/builder-lambda-tra /** * AfterCheck builder-lambda transform with no recheck AST. + * @deprecated */ export const builderLambdaNoRecheck: Plugins = { name: 'builder-lambda-no-recheck', diff --git a/ui2abc/arkui-plugins/test/utils/plugins/collect-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/collect-no-recheck.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8389f7f31d327f49e98dc781ce766f4d5fbf529 --- /dev/null +++ b/ui2abc/arkui-plugins/test/utils/plugins/collect-no-recheck.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 { PluginContext, Plugins } from '../../../common/plugin-context'; +import { ProgramVisitor } from '../../../common/program-visitor'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, NodeCacheNames } from '../../../common/predefines'; +import { Collector } from '../../../collectors/collector'; +import { NodeCacheFactory } from '../../../common/node-cache'; +import { TestGlobal } from '../global'; + +/** + * AfterCheck cache any node that should be ui-transformed or unmemoized with no recheck AST. + */ +export const collectNoRecheck: Plugins = { + name: 'collect-no-recheck', + checked(this: PluginContext): arkts.ETSModule | undefined { + let script: arkts.ETSModule | undefined; + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (((global as TestGlobal).MEMO_CACHE_ENABLED || (global as TestGlobal).UI_CACHE_ENABLED) && !!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + script = program.ast as arkts.ETSModule; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).shouldCollectUpdate((global as TestGlobal).UI_UPDATE_ENABLED); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldCollectUpdate((global as TestGlobal).MEMO_UPDATE_ENABLED); + const collector = new Collector({ + shouldCollectUI: (global as TestGlobal).UI_CACHE_ENABLED, + shouldCollectMemo: (global as TestGlobal).MEMO_CACHE_ENABLED, + }); + const programVisitor = new ProgramVisitor({ + pluginName: collectNoRecheck.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [collector], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: this, + }); + program = programVisitor.programVisitor(program); + script = program.ast as arkts.ETSModule; + return script; + } + return script; + }, +}; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/test/utils/plugins/index.ts b/ui2abc/arkui-plugins/test/utils/plugins/index.ts index ab232c217a4c678d522d4e2c7490ba8723e8c5fd..f3cc2e6d83b5bdb211a18a70e159823db1af44ad 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/index.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/index.ts @@ -18,7 +18,9 @@ export * from './struct-to-component'; // AfterCheck export * from './before-memo-no-recheck'; +export * from './before-ui-no-recheck'; export * from './builder-lambda-no-recheck'; +export * from './collect-no-recheck'; export * from './memo-no-recheck'; export * from './struct-no-recheck'; export * from './ui-no-recheck'; diff --git a/ui2abc/arkui-plugins/test/utils/plugins/memo-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/memo-no-recheck.ts index aa53b4d56c358f5e9744b2dc4d2b64bfbcd87dd0..a2f7e261dc5259dc3663ffa221c253365bbd83e3 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/memo-no-recheck.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/memo-no-recheck.ts @@ -16,14 +16,14 @@ 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'; import { SignatureTransformer } from '../../../memo-plugins/signature-transformer'; import { FunctionTransformer } from '../../../memo-plugins/function-transformer'; import { InternalsTransformer } from '../../../memo-plugins/internal-transformer'; -import { NodeCache } from '../../../common/node-cache'; +import { NodeCacheFactory } from '../../../common/node-cache'; /** * AfterCheck unmemoizeTransform with no recheck AST. @@ -52,7 +52,7 @@ export const memoNoRecheck: Plugins = { returnTransformer, signatureTransformer, internalsTransformer, - useCache: NodeCache.getInstance().isCollected() + useCache: NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).isCollected() }); const skipPrefixNames = isFrameworkMode ? EXTERNAL_SOURCE_PREFIX_NAMES_FOR_FRAMEWORK @@ -65,7 +65,7 @@ export const memoNoRecheck: Plugins = { pluginContext: this, }); program = programVisitor.programVisitor(program); - NodeCache.getInstance().clear(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).clear(); script = program.ast as arkts.ETSModule; return script; } diff --git a/ui2abc/arkui-plugins/test/utils/plugins/struct-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/struct-no-recheck.ts index 9b60340f8cd6ab07f93828eb180dc8cc44666bdd..57936aa8aa1da4b321e5f8df099f1a670944a934 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/struct-no-recheck.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/struct-no-recheck.ts @@ -21,6 +21,7 @@ import { StructTransformer } from '../../../ui-plugins/struct-translators/struct /** * AfterCheck struct transform with no recheck AST. + * @deprecated */ export const structNoRecheck: Plugins = { name: 'struct-no-recheck', diff --git a/ui2abc/arkui-plugins/test/utils/plugins/struct-to-component.ts b/ui2abc/arkui-plugins/test/utils/plugins/struct-to-component.ts index 7c66cba350db5dc736ecbb17879f498dec033491..86171644206f6e149126f76e3769d6563b72b50b 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/struct-to-component.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/struct-to-component.ts @@ -18,6 +18,7 @@ import { PluginContext, Plugins } from '../../../common/plugin-context'; import { ProgramVisitor } from '../../../common/program-visitor'; import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../../../common/predefines'; import { ComponentTransformer } from '../../../ui-plugins/component-transformer'; +import { Collector } from '../../../collectors/collector'; /** * AfterParse transform struct to component. diff --git a/ui2abc/arkui-plugins/test/utils/plugins/ui-no-recheck.ts b/ui2abc/arkui-plugins/test/utils/plugins/ui-no-recheck.ts index c238d78bd02c746ee252fdb4d5f1d9857e42e853..ca7fce0fed7e40c8322d6fd62dbd0c3f855de999 100644 --- a/ui2abc/arkui-plugins/test/utils/plugins/ui-no-recheck.ts +++ b/ui2abc/arkui-plugins/test/utils/plugins/ui-no-recheck.ts @@ -16,8 +16,9 @@ import * as arkts from '@koalaui/libarkts'; import { PluginContext, Plugins } from '../../../common/plugin-context'; import { ProgramVisitor } from '../../../common/program-visitor'; -import { EXTERNAL_SOURCE_PREFIX_NAMES } from '../../../common/predefines'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, NodeCacheNames } from '../../../common/predefines'; import { CheckedTransformer } from '../../../ui-plugins/checked-transformer'; +import { NodeCacheFactory } from '../../../common/node-cache'; /** * AfterCheck uiTransform with no recheck AST. @@ -30,7 +31,10 @@ export const uiNoRecheck: Plugins = { if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.ast as arkts.ETSModule; - const checkedTransformer = new CheckedTransformer(this.getProjectConfig()); + const checkedTransformer = new CheckedTransformer({ + projectConfig: this.getProjectConfig(), + useCache: NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).isCollected(), + }); const programVisitor = new ProgramVisitor({ pluginName: uiNoRecheck.name, state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, diff --git a/ui2abc/arkui-plugins/test/utils/processor-builder.ts b/ui2abc/arkui-plugins/test/utils/processor-builder.ts index 7be32e773b639ff283e5484fe125d6c5d164575b..bf72683f8192a4c15fe9e14ac3a2a1f039b74cce 100644 --- a/ui2abc/arkui-plugins/test/utils/processor-builder.ts +++ b/ui2abc/arkui-plugins/test/utils/processor-builder.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import { ProjectConfig } from 'common/plugin-context'; +import { ProjectConfig } from '../../common/plugin-context'; import { BuildConfig, Processor, TraceOptions } from './shared-types'; class ProcessorBuilder { diff --git a/ui2abc/arkui-plugins/test/utils/simplify-dump.ts b/ui2abc/arkui-plugins/test/utils/simplify-dump.ts index bf59a8f50f06132f01e53a5a99d524520429b969..9ec142d003e28e0463033aef67265c05bc822192 100644 --- a/ui2abc/arkui-plugins/test/utils/simplify-dump.ts +++ b/ui2abc/arkui-plugins/test/utils/simplify-dump.ts @@ -47,7 +47,7 @@ function dumpGetterSetter( body = '{\nthrow new InvalidStoreAccessError();\n}\n'; } } - const strList: string[] = [...annotations, methodStr, ...(!!body ? [body] : [])]; + const strList: string[] = [...annotations.map((str) => `${str} \n`), methodStr, ...(!!body ? [body] : [])]; return strList.join(' '); } diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/bindable-factory.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/bindable-factory.ts index d010157c8bf44f96562ae92fd36da0ca8e055cbd..02697139871c08ec24a11a488eeff0ecffeb924c 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/bindable-factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/bindable-factory.ts @@ -23,157 +23,57 @@ export class BindableFactory { /** * transform bundable arguments in style node, e.g. `Radio().checked($$(this.checked))` => `Radio().checked({value: xxx, onChange: xxx})`. */ - static updateBindableStyleArguments( - arg: arkts.CallExpression | arkts.TSAsExpression, - param: arkts.ETSParameterExpression - ): arkts.Expression { - let _type: arkts.TypeNode | undefined; + static updateBindableStyleArguments(arg: arkts.CallExpression | arkts.TSAsExpression): arkts.Expression { let _call: arkts.CallExpression; if (arkts.isTSAsExpression(arg)) { - _type = arg.typeAnnotation; _call = arg.expr as arkts.CallExpression; } else { - _type = this.findBindableTypeFromType(param.typeAnnotation as arkts.TypeNode); _call = arg; } const bindableArg = _call.arguments.at(0); if (!bindableArg) { return arg; } - const obj: arkts.ObjectExpression = this.generateBindableObjectExpr(bindableArg, _type); - if (!_type) { - return obj; - } - return arkts.factory.createTSAsExpression(obj, _type, false); - } - - /** - * find `Bindable<...>` type from possible union type. - */ - static findBindableTypeFromType(node: arkts.TypeNode | undefined): arkts.TypeNode | undefined { - if (!node) { - return undefined; - } - if (arkts.isETSUnionType(node)) { - for (const type of node.types) { - const bindableType = this.findBindableTypeFromType(type); - if (!!bindableType) { - return bindableType; - } - } - return undefined; - } - if (arkts.isETSTypeReference(node)) { - const part = node.part; - if (!part || !arkts.isETSTypeReferencePart(part) || !part.typeParams) { - return undefined; - } - const name = part.name; - if (!name || !arkts.isIdentifier(name) || name.name !== BindableNames.BINDABLE) { - return undefined; - } - return node; - } - return undefined; - } - - /** - * generate bindable rewrite object expression. - */ - static generateBindableObjectExpr( - bindableArg: arkts.Expression, - valueType: arkts.TypeNode | undefined - ): arkts.ObjectExpression { - ImportCollector.getInstance().collectImport(BindableNames.BINDABLE); - return arkts.factory.createObjectExpression( - [this.generateValueProperty(bindableArg), this.generateOnChangeArrowFunc(bindableArg, valueType)] - ); - } - - /** - * generate `value: ` in object. - */ - static generateValueProperty(bindableArg: arkts.Expression): arkts.Property { - return arkts.factory.createProperty( - arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, - arkts.factory.createIdentifier(BindableNames.VALUE), - bindableArg.clone(), - false, - false - ); + return BindableFactory.generateMakeBindableCall(bindableArg); } /** - * generate `onChange: (value: ) => = value` in object. + * generate bindable rewrite call. */ - static generateOnChangeArrowFunc( - bindableArg: arkts.Expression, - bindableType: arkts.TypeNode | undefined - ): arkts.Property { - const ident = arkts.factory.createIdentifier(BindableNames.VALUE); - const valueType = this.findInnerTypeFromBindableType(bindableType as arkts.ETSTypeReference); - if (!!valueType) { - ident.setTsTypeAnnotation(valueType.clone()); - } - return arkts.factory.createProperty( - arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, - arkts.factory.createIdentifier(BindableNames.ON_CHANGE), - PropertyFactory.createArrowFunctionWithParamsAndBody( - undefined, - [arkts.factory.createETSParameterExpression(ident, false, undefined)], - undefined, - false, - [ - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - bindableArg.clone(), + static generateMakeBindableCall(bindableArg: arkts.Expression): arkts.CallExpression { + ImportCollector.getInstance().collectImport(BindableNames.MAKE_BINDABLE); + return arkts.factory.createCallExpression( + arkts.factory.createIdentifier(BindableNames.MAKE_BINDABLE), + [ + bindableArg, + PropertyFactory.createArrowFunctionWithParamsAndBody( + undefined, + [ + arkts.factory.createETSParameterExpression( arkts.factory.createIdentifier(BindableNames.VALUE), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ), - ] - ), + false, + undefined + ), + ], + undefined, + false, + [ + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + bindableArg.clone(), + arkts.factory.createIdentifier(BindableNames.VALUE), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ), + ] + ), + ], + undefined, false, false ); } - /** - * find `xxx` type from `Bindable` type - */ - static findInnerTypeFromBindableType(node: arkts.ETSTypeReference | undefined): arkts.TypeNode | undefined { - if (!node) { - return undefined; - } - const part = node.part as arkts.ETSTypeReferencePart; - return part.typeParams?.params.at(0); - } - - /** - * find value type from bindable property, e.g. find type of `text` from `text: $$(...)` - */ - static findBindablePropertyValueType(property: arkts.Property): arkts.TypeNode | undefined { - const key = property.key; - const decl = key ? arkts.getDecl(key) : undefined; - if (!decl) { - return undefined; - } - if (arkts.isClassProperty(decl)) { - return decl.typeAnnotation; - } - if (arkts.isMethodDefinition(decl)) { - const kind = decl.kind; - if (kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { - return decl.function.returnTypeAnnotation; - } - if (kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { - const param = decl.function.params.at(0) as arkts.ETSParameterExpression | undefined; - return param?.typeAnnotation as arkts.TypeNode | undefined; - } - } - return undefined; - } - /** * update bindableProperty, e.g. `text: $$(this.text)` => `text: { value: xxx , onChange: xxx }`. */ @@ -181,38 +81,16 @@ export class BindableFactory { prop: arkts.Property, value: arkts.CallExpression | arkts.TSAsExpression ): arkts.Property { - let _type: arkts.TypeNode | undefined; let _value: arkts.CallExpression; if (arkts.isTSAsExpression(value)) { - _type = value.typeAnnotation; _value = value.expr as arkts.CallExpression; } else { - _type = this.findBindableTypeFromType(this.findBindablePropertyValueType(prop)); _value = value; } const bindableArg = _value.arguments.at(0); if (!bindableArg) { return prop; } - const obj: arkts.ObjectExpression = this.generateBindableObjectExpr(bindableArg, _type); - if (!_type) { - return arkts.factory.updateProperty(prop, prop.kind, prop.key, obj, prop.isMethod, prop.isComputed); - } - return arkts.factory.updateProperty(prop, prop.kind, prop.key, arkts.factory.createTSAsExpression(obj, _type, false), prop.isMethod, prop.isComputed); - } - - /** - * generate `Bindable` - * @deprecated - */ - static createBindableType(valueType: arkts.TypeNode): arkts.ETSTypeReference { - const transformedKey = BindableNames.BINDABLE; - ImportCollector.getInstance().collectImport(transformedKey); - return arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier(transformedKey), - arkts.factory.createTSTypeParameterInstantiation([valueType.clone()]) - ) - ); + return arkts.factory.updateProperty(prop, prop.kind, prop.key, BindableFactory.generateMakeBindableCall(bindableArg), prop.isMethod, prop.isComputed); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/builder-factory.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/builder-factory.ts index 73ef23273c4f061052dc684bdb5eb051a6f63bf0..333907e09a25fe5d25f3a743a792d1ae5b877b81 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/builder-factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/builder-factory.ts @@ -99,7 +99,8 @@ export class BuilderFactory { return _node; } const newValue = BuilderFactory.rewriteBuilderArrowFunction(value); - return arkts.factory.updateProperty(_node, _node.kind, _node.key, newValue, _node.isMethod, _node.isComputed); + _node.setValue(newValue); + return _node; } /** diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache-factory.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..feb6df27a09eb64ac82b17a725f50887a6157b35 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache-factory.ts @@ -0,0 +1,599 @@ +/* + * 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, + checkIsTrailingLambdaInLastParam, + CustomComponentInterfacePropertyInfo, + FunctionInfo, + InnerComponentFunctionInfo, + StructMethodInfo, +} from '../../collectors/ui-collectors/records'; +import { + checkIsFunctionMethodDeclFromInfo, + collectStructPropertyInfos, +} from '../../collectors/ui-collectors/utils'; +import { + AnimationNames, + BuilderLambdaNames, + NodeCacheNames, + StateManagementTypes, +} from '../../common/predefines'; +import { + annotation, + backingField, + collect, + filterDefined, + forEachArgWithParam, + removeAnnotationByName, +} from '../../common/arkts-utils'; +import { getPerfName } from '../../common/debug'; +import { + MemoNames, +} from '../../collectors/memo-collectors/utils'; +import { ConditionScopeCacheVisitor } from '../condition-scope-translators/condition-scope-visitor'; +import { factory as TypeFactory } from '../type-translators/factory'; +import { factory as UIFactory } from '../ui-factory'; +import { factory as BuilderLambdaFactory } from './factory'; +import { optionsHasField } from '../utils'; +import { InnerComponentInfoCache } from './cache/innerComponentInfoCache'; +import { ComponentRecord } from './cache/componentAttributeCache'; +import { + BuilderLambdaChainingCallArgInfo, + BuilderLambdaDeclInfo, + builderLambdaMethodDeclType, + BuilderLambdaStyleBodyInfo, + builderLambdaType, + buildSecondLastArgInfo, + collectDeclInfoFromInfo, + getDeclaredSetAttribtueMethodName, + InstanceCallInfo, + isDoubleDollarCall, + isStyleChainedCallee, + isStyleWithReceiverCallee, + OptionsPropertyInfo, + replaceBuilderLambdaDeclMethodName, +} from './utils'; +import { BindableFactory } from './bindable-factory'; +import { BuilderParamPropertyCache, ConditionScopeInfoCache, InitialBuilderLambdaBodyCache } from '../memo-collect-cache'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export class CacheFactory { + /** + * add declared set methods in `@ComponentBuilder` Attribute interface + */ + static addDeclaredSetMethodsInAttributeInterface( + node: arkts.TSInterfaceDeclaration, + componentName: string + ): arkts.TSInterfaceDeclaration { + if (!node.body) { + return node; + } + const infos = InnerComponentInfoCache.getInstance().getComponentRecord(componentName); + if (!infos || infos.length === 0) { + return node; + } + const overloads = infos.map((info) => this.createDeclaredSetMethodFromInfo(info, componentName)); + return arkts.factory.updateInterfaceDeclaration( + node, + node.extends, + node.id, + node.typeParams, + arkts.factory.updateInterfaceBody(node.body, [...node.body.body, ...overloads]), + node.isStatic, + node.isFromExternal + ); + } + + /** + * generate declared set method from `InnerComponentFunctionInfo` + */ + static createDeclaredSetMethodFromInfo( + info: InnerComponentFunctionInfo, + componentName: string + ): arkts.MethodDefinition { + const name = getDeclaredSetAttribtueMethodName(componentName); + const hasReceiver = !!info.hasReceiver; + const params = info.paramRecords?.map((record) => TypeFactory.createParameterFromRecord(record)) ?? []; + const typeParams = info.typeParameters?.map((p) => TypeFactory.createTypeParameterFromRecord(p)); + + const key = arkts.factory.createIdentifier(name); + const kind = arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD; + const modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; + const funcTypeParams = typeParams + ? arkts.factory.createTSTypeParameterDeclaration(typeParams, typeParams.length) + : undefined; + const returnTypeAnnotation = arkts.factory.createTSThisType(); + const flags = arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD; + + return UIFactory.createMethodDefinition({ + key, + kind, + function: { + key, + flags, + params, + typeParams: funcTypeParams, + returnTypeAnnotation, + modifiers, + hasReceiver, + }, + modifiers, + }); + } + + /** + * create all `@ComponentBuilder` component Impl functions for each unique component name. + */ + static createAllUniqueDeclaredComponentFunctions( + componentNames: string[], + cache: InnerComponentInfoCache + ): arkts.MethodDefinition[] { + const methods: arkts.MethodDefinition[] = []; + componentNames.forEach((name: string) => { + const info = cache.getComponentRecord(name)?.at(0); + const hasLastTrailingLambda = cache.getHasLastTrailingLambda(name); + const attributeName = cache.getAttributeName(name); + const attributeTypeParams = cache.getAttributeTypeParams(name); + if (!info || !attributeName) { + return; + } + const componentImplMethod = BuilderLambdaFactory.createDeclaredComponentFunctionFromRecord( + { name, ...info } as ComponentRecord, + hasLastTrailingLambda, + attributeName, + attributeTypeParams + ); + methods.push(componentImplMethod); + }); + return methods; + } + + /** + * transform `@ComponentBuilder` in declared methods. + */ + static transformBuilderLambdaMethodDeclFromInfo( + node: arkts.MethodDefinition, + metadata: StructMethodInfo | FunctionInfo, + isFromStruct?: boolean + ): arkts.MethodDefinition { + if (!metadata.name) { + return node; + } + if (!isFromStruct && checkIsFunctionMethodDeclFromInfo(metadata)) { + InnerComponentInfoCache.getInstance().collect(metadata.name, metadata.innerComponentInfo); + } + const func: arkts.ScriptFunction = node.function; + const typeNode: arkts.TypeNode | undefined = builderLambdaMethodDeclType(node); + const newNode = BuilderLambdaFactory.updateBuilderLambdaMethodDecl( + node, + [BuilderLambdaFactory.createStyleArgInBuilderLambdaDecl(typeNode)], + removeAnnotationByName(func.annotations, BuilderLambdaNames.ANNOTATION_NAME), + replaceBuilderLambdaDeclMethodName(metadata.name), + [...node.overloads] + ); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); + return newNode; + } + + /** + * transform `@ComponentBuilder` in non-declared calls. + */ + static transformBuilderLambdaFromInfo(node: arkts.CallExpression, metadata: CallInfo): arkts.CallExpression { + const rootCallInfo: CallInfo = metadata.rootCallInfo ?? metadata; + if (!rootCallInfo.declName) { + return node; + } + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 1], 'find instance style')); + let instanceCalls: InstanceCallInfo[] = []; + const animateStartStacks: InstanceCallInfo[] = []; + let leaf: arkts.CallExpression = node; + const chainingCallInfos = metadata.chainingCallInfos ?? []; + while (chainingCallInfos.length > 0) { + const chainedCallInfo = chainingCallInfos.pop()!; + const callee = leaf.callee!; + const updateInfo = this.createInstanceCallUpdateInfo(callee, leaf, chainedCallInfo); + if (!updateInfo) { + continue; + } + if (updateInfo.instanceCalls.length > 1 && updateInfo.hasAnimate) { + instanceCalls.push(updateInfo.instanceCalls.at(0)!); + animateStartStacks.push(updateInfo.instanceCalls.at(1)!); + } else { + instanceCalls.push(...updateInfo.instanceCalls); + while (animateStartStacks.length > 0) { + instanceCalls.push(animateStartStacks.pop()!); + } + } + leaf = updateInfo.leaf; + } + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 1], 'find instance style')); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 2], 'findBuilderLambdaDeclInfo')); + const declInfo: BuilderLambdaDeclInfo | undefined = collectDeclInfoFromInfo(leaf, rootCallInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 2], 'findBuilderLambdaDeclInfo')); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 3], 'builderLambdaReplace')); + const replace: arkts.Identifier | arkts.MemberExpression | undefined = + BuilderLambdaFactory.builderLambdaReplace(leaf, declInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 3], 'builderLambdaReplace')); + if (!replace || !declInfo) { + return node; + } + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 4], 'createInitLambdaBody')); + const lambdaBodyInfo = BuilderLambdaFactory.createInitLambdaBody(declInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 4], 'createInitLambdaBody')); + let lambdaBody: arkts.Identifier | arkts.CallExpression | undefined = lambdaBodyInfo.lambdaBody; + if (instanceCalls.length > 0) { + instanceCalls = instanceCalls.reverse(); + instanceCalls.forEach((callInfo) => { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 5], 'createStyleLambdaBody')); + lambdaBody = this.createStyleLambdaBody(lambdaBody!, callInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 5], 'createStyleLambdaBody')); + }); + } + lambdaBodyInfo.lambdaBody = lambdaBody; + lambdaBodyInfo.structPropertyInfos = + !!declInfo && !declInfo.isFunctionCall ? collectStructPropertyInfos(metadata) : undefined; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 5], 'generateArgsInBuilderLambda')); + const args: (arkts.Expression | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBodyInfo, declInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 5], 'generateArgsInBuilderLambda')); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 6], 'update builderLambda Call')); + const newNode = arkts.factory.updateCallExpression(node, replace, filterDefined(args), leaf.typeParams); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 6], 'update builderLambda Call')); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + InitialBuilderLambdaBodyCache.getInstance().updateAll().reset(); + BuilderParamPropertyCache.getInstance().updateAll().reset(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); + return newNode; + } + + /** + * create style instance call, e.g. `instance.margin(10)`. + */ + static createStyleLambdaBody(lambdaBody: arkts.Expression, callInfo: InstanceCallInfo): arkts.CallExpression { + const oriCall: arkts.CallExpression = callInfo.call; + let call: arkts.CallExpression; + if (!callInfo.isReceiver) { + const argInfos: BuilderLambdaChainingCallArgInfo[] = BuilderLambdaFactory.getTransformedStyle(oriCall); + call = arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + lambdaBody, + oriCall.callee, + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + argInfos.map((info) => { + return info.arg; + }), + undefined, + false, + false + ); + } else { + call = arkts.factory.createCallExpression( + oriCall.callee, + [lambdaBody, ...oriCall.arguments.slice(1)], + oriCall.typeParams, + oriCall.isOptional, + oriCall.hasTrailingComma + ); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(call, { hasReceiver: true }); + } + return call; + } + + static createInstanceCallUpdateInfo( + callee: arkts.Expression, + oriLeaf: arkts.CallExpression, + info: CallInfo + ): { instanceCalls: InstanceCallInfo[]; leaf: arkts.CallExpression; hasAnimate?: boolean } | undefined { + const isReceiver = !!info?.hasReceiver; + if (isStyleChainedCallee(callee)) { + return { + ...this.updateStyleChainedInstanceCallsFromInfo(callee, oriLeaf, info), + leaf: callee.object as arkts.CallExpression, + }; + } + if (isStyleWithReceiverCallee(oriLeaf, callee, isReceiver)) { + return { + instanceCalls: [ + { + isReceiver, + call: arkts.factory.createCallExpression(callee, oriLeaf.arguments, oriLeaf.typeParams, false, false), + }, + ], + leaf: oriLeaf.arguments[0] as arkts.CallExpression, + }; + } + return undefined; + } + + static updateStyleChainedInstanceCallsFromInfo( + callee: arkts.MemberExpression, + oriLeaf: arkts.CallExpression, + info: CallInfo + ): { instanceCalls: InstanceCallInfo[]; hasAnimate?: boolean } { + const name: string = info.declName!; + const _callee: arkts.Expression = callee.property!; + const _typeArguments = oriLeaf.typeParams; + const _arguments = oriLeaf.arguments; + if (name !== AnimationNames.ANIMATION) { + return { + instanceCalls: [ + { + isReceiver: false, + call: arkts.factory.createCallExpression(_callee, _arguments, _typeArguments, false, false), + }, + ], + }; + } + const aniStart: arkts.CallExpression = arkts.factory.createCallExpression( + arkts.factory.createIdentifier(AnimationNames.ANIMATION_START), + _arguments, + undefined, + false, + false + ); + const aniStop: arkts.CallExpression = arkts.factory.createCallExpression( + arkts.factory.createIdentifier(AnimationNames.ANIMATION_STOP), + _arguments.map((arg) => arg.clone()), + undefined, + false, + false + ); + // instance calls are inversed so animationStop(...) should before animationStart(...). + return { + instanceCalls: [ + { isReceiver: false, call: aniStop }, + { isReceiver: false, call: aniStart }, + ], + hasAnimate: true, + }; + } + + /** + * transform arguments in a builder lambda call. + */ + static generateArgsInBuilderLambda( + leaf: arkts.CallExpression, + lambdaBodyInfo: BuilderLambdaStyleBodyInfo, + declInfo: BuilderLambdaDeclInfo + ): (arkts.Expression | undefined)[] { + const { isFunctionCall, params, returnType, moduleName, isTrailingCall, isFromCommonMethod } = declInfo; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 5, 1], 'builderLambdaType')); + const type: arkts.Identifier | undefined = builderLambdaType(leaf); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 5, 1], 'builderLambdaType')); + const args: (arkts.Expression | undefined)[] = []; + const modifiedArgs: (arkts.Expression | undefined)[] = []; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 5, 2], 'buildSecondLastArgInfo')); + const secondLastArgInfo = buildSecondLastArgInfo(type, isFunctionCall); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 5, 2], 'buildSecondLastArgInfo')); + const _isTrailingCall = isTrailingCall ?? leaf.isTrailingCall; + const typeArguments = leaf.typeParams; + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 0, 5, 3], 'checkIsTrailingLambdaInLastParam') + ); + const hasLastTrailingLambda = checkIsTrailingLambdaInLastParam(params); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 0, 5, 3], 'checkIsTrailingLambdaInLastParam') + ); + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0, 5, 4], 'forEachArgWithParam')); + forEachArgWithParam( + leaf.arguments, + params, + (arg, param, index) => { + const isLastTrailingLambda = index === params.length - 1 && hasLastTrailingLambda; + let modifiedArg: arkts.Expression | undefined; + if (index === params.length - 2 && !arg) { + modifiedArg = BuilderLambdaFactory.createSecondLastArgInBuilderLambda(secondLastArgInfo); + } + if (!modifiedArg) { + const fallback = arkts.factory.createUndefinedLiteral(); + const updatedArg = this.createOrUpdateArgInBuilderLambda( + fallback, + arg, + param, + isLastTrailingLambda, + declInfo, + lambdaBodyInfo.structPropertyInfos + ); + modifiedArg = BuilderLambdaFactory.processModifiedArg( + updatedArg, + index, + leaf.arguments, + moduleName, + type?.name + ); + } + if (!isFunctionCall || isLastTrailingLambda) { + args.push(modifiedArg); + } else { + modifiedArgs.push(modifiedArg); + } + }, + { isTrailingCall: _isTrailingCall } + ); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0, 5, 4], 'forEachArgWithParam')); + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 0, 5, 5], 'addOptionsArgsToLambdaBodyInStyleArg') + ); + const lambdaBody = BuilderLambdaFactory.addOptionsArgsToLambdaBodyInStyleArg( + lambdaBodyInfo, + modifiedArgs, + typeArguments?.params, + isFromCommonMethod + ); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 0, 5, 5], 'addOptionsArgsToLambdaBodyInStyleArg') + ); + const typeNode = !isFunctionCall && !!type ? UIFactory.createTypeReferenceFromString(type.name) : returnType; + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 0, 5, 5], 'createStyleArgInBuilderLambda') + ); + const styleArg = BuilderLambdaFactory.createStyleArgInBuilderLambda(lambdaBody, typeNode, moduleName); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 0, 5, 5], 'createStyleArgInBuilderLambda') + ); + args.unshift(styleArg); + return args; + } + + /** + * create or update arguments in a builder lambda call. + * If the corresponding argument is not provided, fill-in an `undefined` to it. + */ + static createOrUpdateArgInBuilderLambda( + fallback: arkts.Expression | undefined, + arg: arkts.Expression | undefined, + param: arkts.Expression, + hasBuilder?: boolean, + declInfo?: BuilderLambdaDeclInfo, + structPropertyInfos?: CustomComponentInterfacePropertyInfo[] + ): arkts.Expression | undefined { + if (!arg) { + return fallback; + } + if (arkts.isArrowFunctionExpression(arg)) { + let _arg = !!hasBuilder ? this.updateBuilderArrowFunction(arg) : arg; + if (NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(param)) { + const metadata = NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .get(param)?.metadata; + _arg.setAnnotations([annotation(MemoNames.MEMO_UI)]); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(_arg, metadata); + } + return _arg; + } + // this is too optimistic to check if this is an options argument... + if (arkts.isTSAsExpression(arg) || arkts.isObjectExpression(arg)) { + return this.processOptionsArg(arg, declInfo, structPropertyInfos); + } + return arg; + } + + static updateBuilderArrowFunction(func: arkts.ArrowFunctionExpression): arkts.ArrowFunctionExpression { + const conditionScopeVisitor = ConditionScopeCacheVisitor.getInstance(); + const scriptFunc = func.function; + const body = scriptFunc.body! as arkts.BlockStatement; + body.setStatements( + body.statements.map((st) => { + const newNode = conditionScopeVisitor.visitor(st); + conditionScopeVisitor.reset(); + return newNode as arkts.Statement; + }) + ); + func.setAnnotations([annotation(MemoNames.MEMO_UI)]); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + return func; + } + + /** + * transform options argument in a builder lambda call. + */ + static processOptionsArg( + arg: T, + declInfo?: BuilderLambdaDeclInfo, + structPropertyInfos?: CustomComponentInterfacePropertyInfo[] + ): T { + let expr: arkts.ObjectExpression | undefined; + if (arkts.isTSAsExpression(arg) && !!arg.expr && arkts.isObjectExpression(arg.expr)) { + expr = arg.expr; + } else if (arkts.isObjectExpression(arg)) { + expr = arg; + } + if (!expr) { + return arg; + } + const properties = (expr.properties as arkts.Property[]).map((p, idx) => { + return this.updatePropertiesInOptions(p, declInfo, structPropertyInfos?.at(idx)); + }); + const updatedExpr: arkts.ObjectExpression = arkts.ObjectExpression.updateObjectExpression( + expr, + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + collect(...properties), + false + ); + if (arkts.isTSAsExpression(arg)) { + return arkts.TSAsExpression.updateTSAsExpression(arg, updatedExpr, arg.typeAnnotation, arg.isConst) as T; + } + return updatedExpr as T; + } + + static updatePropertiesInOptions( + prop: arkts.Property, + declInfo?: BuilderLambdaDeclInfo, + propertyInfo?: CustomComponentInterfacePropertyInfo + ): arkts.Property[] { + const key: arkts.AstNode | undefined = prop.key; + const value: arkts.Expression | undefined = prop.value; + if (!key || !arkts.isIdentifier(key) || !value) { + return [prop]; + } + const isNotBacking: boolean = !propertyInfo?.name?.startsWith(StateManagementTypes.BACKING); + const isBuilderParam: boolean = !!propertyInfo?.annotationInfo?.hasBuilderParam; + const isLink: boolean = !!propertyInfo?.annotationInfo?.hasLink; + return this.updateSpecificProperties(prop, key, value, { isBuilderParam, isLink, isNotBacking }, declInfo); + } + + static updateSpecificProperties( + prop: arkts.Property, + key: arkts.Identifier, + value: arkts.Expression, + propertyInfo: OptionsPropertyInfo, + declInfo?: BuilderLambdaDeclInfo + ): arkts.Property[] { + const keyName: string = key.name; + let newProperty: arkts.Property = prop; + const isBuilder = ( + propertyInfo.isBuilderParam || + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(prop) || + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(value) + ); + if (isDoubleDollarCall(value)) { + newProperty = BindableFactory.updateBindableProperty(prop, value); + } else if (isBuilder && arkts.isArrowFunctionExpression(value)) { + newProperty = prop.setValue(this.updateBuilderArrowFunction(value)); + BuilderParamPropertyCache.getInstance().collect({ node: newProperty }); + } else if ( + propertyInfo.isLink && + propertyInfo.isNotBacking && + arkts.isMemberExpression(value) && + arkts.isThisExpression(value.object) && + arkts.isIdentifier(value.property) + ) { + newProperty = arkts.factory.updateProperty( + prop, + prop.kind, + arkts.factory.createIdentifier(backingField(keyName)), + BuilderLambdaFactory.updateBackingMember(value, value.property.name), + false, + false + ); + } + return declInfo?.isFunctionCall + ? [newProperty] + : [ + newProperty, + arkts.factory.createProperty( + arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, + arkts.factory.createIdentifier(optionsHasField(keyName)), + arkts.factory.createBooleanLiteral(true), + false, + false + ), + ]; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts index e3a1b93c59c2ae068b268fbe7c933e9bfba7d1e3..356569abd8937402877f2657d46d1b45ce805131 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/componentAttributeCache.ts @@ -14,6 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; +import { expectNameInTypeReference } from '../../../common/arkts-utils'; import { collectTypeRecordFromParameter, collectTypeRecordFromTypeParameterDeclaration, @@ -22,9 +23,8 @@ import { TypeParameterTypeRecord, TypeRecord, } from '../../../collectors/utils/collect-types'; -import { checkIsTrailingLambdaInLastParam, isForEach } from '../utils'; +import { checkIsTrailingLambdaInLastParam, isForEach } from '../../../collectors/ui-collectors/records'; import { factory as UIFactory } from '../../ui-factory'; -import { expectNameInTypeReference } from '../../utils'; export interface ComponentRecord { name: string; @@ -47,7 +47,7 @@ function findAttributeInfoFromComponentMethod(component: arkts.MethodDefinition) const type = component.function.returnTypeAnnotation; const name = expectNameInTypeReference(type); if (!name) { - return; + return undefined; } return { name: name.name, @@ -82,9 +82,9 @@ export class ComponentAttributeCache { } private collectComponentRecord(name: string, record: ComponentRecord): void { - const collectedRecords: ComponentRecord[] = this._cache.get(name) ?? []; - collectedRecords.push(record); - this._cache.set(name, collectedRecords); + const colelctedRecords: ComponentRecord[] = this._cache.get(name) ?? []; + colelctedRecords.push(record); + this._cache.set(name, colelctedRecords); } private collectAttributeName(name: string, attributeName: string): void { @@ -109,14 +109,9 @@ export class ComponentAttributeCache { index: number, name: string ): arkts.ETSParameterExpression { - if (index === 0 && isForEach(name) && !!param.typeAnnotation && arkts.isTypeNode(param.typeAnnotation)) { - return arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier( - param.ident!.name, - UIFactory.createLambdaFunctionType([], param.typeAnnotation.clone()) - ), - false - ); + if (index === 0 && isForEach(name) && arkts.isTypeNode(param.typeAnnotation)) { + param.setTypeAnnotation(UIFactory.createLambdaFunctionType([], param.typeAnnotation.clone())) + return param; } return param; } diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/innerComponentInfoCache.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/innerComponentInfoCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe6dbe0e3e18992a14ebb4ee5809d303b913a4b9 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/cache/innerComponentInfoCache.ts @@ -0,0 +1,114 @@ +/* + * 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 { InnerComponentFunctionInfo } from '../../../collectors/ui-collectors/records'; +import { TypeRecord } from '../../../collectors/utils/collect-types'; + +export class InnerComponentInfoCache { + private _cache: Map; + private _componentNames: Set; + private _hasLastTrailingLambda: Record; + private _attributeNameMap: Record; + private _attributeTypeParamsMap: Record; + private _isCollected: boolean = false; + private static instance: InnerComponentInfoCache; + + private constructor() { + this._cache = new Map(); + this._componentNames = new Set(); + this._attributeNameMap = {}; + this._attributeTypeParamsMap = {}; + this._hasLastTrailingLambda = {}; + } + + static getInstance(): InnerComponentInfoCache { + if (!this.instance) { + this.instance = new InnerComponentInfoCache(); + } + return this.instance; + } + + private collectComponentRecord(name: string, info: InnerComponentFunctionInfo): void { + const collectedInfos: InnerComponentFunctionInfo[] = this._cache.get(name) ?? []; + collectedInfos.push(info); + this._cache.set(name, collectedInfos); + } + + private collectAttributeName(name: string, attributeName: string): void { + const collectedNames: string = this._attributeNameMap[name] ?? attributeName; + this._attributeNameMap[name] = collectedNames; + } + + private collectAttributeTypeParams(name: string, attributeTypeParams: TypeRecord[] | undefined): void { + if (!attributeTypeParams) { + return; + } + const collectedTypeParams: TypeRecord[] = this._attributeTypeParamsMap[name] ?? attributeTypeParams; + this._attributeTypeParamsMap[name] = collectedTypeParams; + } + + private collectHasLastTrailingLambda(name: string, hasLastTrailingLambda: boolean): void { + this._hasLastTrailingLambda[name] ||= hasLastTrailingLambda; + } + + reset(): void { + this._cache.clear(); + this._componentNames.clear(); + this._attributeNameMap = {}; + this._attributeTypeParamsMap = {}; + this._hasLastTrailingLambda = {}; + this._isCollected = false; + } + + isCollected(): boolean { + return this._isCollected; + } + + hasComponentName(name: string): boolean { + return this._componentNames.has(name); + } + + collect(componentName?: string, info?: InnerComponentFunctionInfo): void { + if (!componentName || !info || !info.attributeName) { + return; + } + this.collectComponentRecord(componentName, info); + this.collectHasLastTrailingLambda(componentName, !!info.hasLastTrailingLambda); + this.collectAttributeName(componentName, info.attributeName); + this.collectAttributeTypeParams(componentName, info.attributeTypeParams); + this._componentNames.add(componentName); + this._isCollected = true; + } + + getComponentRecord(name: string): InnerComponentFunctionInfo[] | undefined { + return this._cache.get(name); + } + + getAttributeName(name: string): string | undefined { + return this._attributeNameMap[name]; + } + + getAttributeTypeParams(name: string): TypeRecord[] | undefined { + return this._attributeTypeParamsMap[name]; + } + + getHasLastTrailingLambda(name: string): boolean { + return !!this._hasLastTrailingLambda[name]; + } + + getAllComponentNames(): string[] { + return Array.from(this._componentNames.values()); + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/condition-scope-visitor.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/condition-scope-visitor.ts index 8bfebb11852bec78ee543bf34fa6a27ce0a343f1..19985a84c8a6cb3d32a10fa868a9a04147e6fe65 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/condition-scope-visitor.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/condition-scope-visitor.ts @@ -15,7 +15,9 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; +import { NodeCacheNames } from '../../common/predefines'; import { factory as BuilderLambdaFactory } from './factory'; +import { NodeCacheFactory } from '../../common/node-cache'; /** * `ConditionScopeVisitor` is used to visit `@Builder` function body to wrap `ConditionScope`/`ConditionBranch` @@ -55,7 +57,10 @@ export class ConditionScopeVisitor extends AbstractVisitor { } private enter(node: arkts.AstNode): void { - if (arkts.isVariableDeclarator(node) && arkts.MemoNodeCache.getInstance().has(node)) { + if ( + arkts.isVariableDeclarator(node) && + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) + ) { this._enforceUpdateCondition = true; } } @@ -81,8 +86,8 @@ export class ConditionScopeVisitor extends AbstractVisitor { } if ( arkts.isArrowFunctionExpression(node) && - !arkts.MemoNodeCache.getInstance().has(node) && - !arkts.MemoNodeCache.getInstance().has(node.function) + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) && + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node.function) ) { this.shouldUpdateCondition = false; this._enforceUpdateCondition = false; diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index c22e31be3a0465632b44c5146c5656fbf7e108c6..e3959918c03b931a57f3d85d0b35401d33d781f2 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -25,6 +25,7 @@ import { collect, } from '../../common/arkts-utils'; import { GlobalMemoPluginContext, MemoPluginContext } from '@ohos/arkts-compiler-infra'; +import { NodeCacheFactory } from '../../common/node-cache'; import { BuilderLambdaDeclInfo, builderLambdaFunctionName, @@ -47,15 +48,13 @@ import { checkIsWithInIfConditionScope, BuilderLambdaConditionBranchInfo, BuilderLambdaChainingCallArgInfo, - getArgumentType, BuilderLambdaStyleBodyInfo, getDeclaredSetAttribtueMethodName, - checkIsTrailingLambdaInLastParam, getTransformedComponentName, flatObjectExpressionToEntries, OptionsPropertyInfo, } from './utils'; -import { hasDecorator, isDecoratorIntrinsicAnnotation } from '../property-translators/utils'; +import { checkIsNameStartWithBackingField, hasDecorator } from '../property-translators/utils'; import { BuilderFactory } from './builder-factory'; import { BindableFactory } from './bindable-factory'; import { factory as TypeFactory } from '../type-translators/factory'; @@ -65,9 +64,9 @@ import { AnimationNames, ARKUI_BUILDER_SOURCE_NAME, ConditionNames, - DecoratorIntrinsicNames, DecoratorNames, MEMO_IMPORT_SOURCE_NAME, + NodeCacheNames, StateManagementTypes, TypeNames, } from '../../common/predefines'; @@ -79,15 +78,16 @@ import { collectMemoableInfoInFunctionReturnType, collectMemoableInfoInParameter, collectScriptFunctionReturnTypeFromInfo, - findCanAddMemoFromArrowFunction, - MemoNames, + findCanAddMemoFromArrowFunction, MemoNames, } from '../../collectors/memo-collectors/utils'; import { TypeRecord } from '../../collectors/utils/collect-types'; import { StyleInternalsVisitor } from './style-internals-visitor'; -import { ConditionBreakCache } from './cache/conditionBreakCache'; +import { ConditionBreakCache } from '../condition-scope-translators/cache/conditionBreakCache'; import { ComponentAttributeCache, ComponentRecord } from './cache/componentAttributeCache'; -import { isForEach } from './utils'; +import { checkIsTrailingLambdaInLastParam, isForEach } from '../../collectors/ui-collectors/records'; +import { InitialBuilderLambdaBodyCache } from '../memo-collect-cache'; import { useImprovedPlugin } from '../../common/use-improved-memo-plugin'; + export class factory { static globalMemoPluginContext?: GlobalMemoPluginContext static memoPluginContext?: MemoPluginContext @@ -157,7 +157,7 @@ export class factory { (arg, param, index) => { const _param = param as arkts.ETSParameterExpression; if (index === 0 && !!arg && isDoubleDollarCall(arg)) { - argInfo.push({ arg: BindableFactory.updateBindableStyleArguments(arg, _param) }); + argInfo.push({ arg: BindableFactory.updateBindableStyleArguments(arg) }); } else if (!!arg) { argInfo.push({ arg, hasBuilder: hasDecorator(_param, DecoratorNames.BUILDER) }); } @@ -215,7 +215,7 @@ export class factory { if (useImprovedPlugin && factory.memoPluginContext && arkts.isIdentifier(lambdaBody)) { factory.memoPluginContext.registerAdditionalIdentifier(lambdaBody) } - arkts.MemoNodeCache.getInstance().collect(lambdaBody); + InitialBuilderLambdaBodyCache.getInstance().collect({ node: lambdaBody }); const methodName = arkts.factory.createIdentifier(getDeclaredSetAttribtueMethodName(name)); if (!hasReceiver) { lambdaBodyInfo.lambdaBody = arkts.factory.createCallExpression( @@ -273,7 +273,7 @@ export class factory { ); const returnStatement = arkts.factory.createReturnStatement(); - arkts.MemoNodeCache.getInstance().collect(returnStatement); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(returnStatement); const body: arkts.BlockStatement = arkts.factory.createBlockStatement([ arkts.factory.createExpressionStatement(lambdaBody), returnStatement, @@ -323,7 +323,7 @@ export class factory { undefined ); factory.putMemoSkipAnnotationOnParam(parameter); - arkts.MemoNodeCache.getInstance().collect(parameter); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(parameter); return parameter; } @@ -346,7 +346,7 @@ export class factory { true, undefined ); - arkts.MemoNodeCache.getInstance().collect(parameter); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(parameter); return parameter; } @@ -423,17 +423,18 @@ export class factory { if (!key || !arkts.isIdentifier(key) || !value) { return [prop]; } - const propertyDecl: arkts.AstNode | undefined = arkts.getDecl(key); + const propertyDecl: arkts.AstNode | undefined = arkts.getPeerPropertyDecl(prop.peer); if (!propertyDecl || !arkts.isMethodDefinition(propertyDecl)) { return [prop]; } + const isNotBacking: boolean = !checkIsNameStartWithBackingField(propertyDecl.id); let isBuilderParam: boolean = false; - let isLinkIntrinsic: boolean = false; + let isLink: boolean = false; propertyDecl.function.annotations.forEach((anno) => { isBuilderParam ||= isDecoratorAnnotation(anno, DecoratorNames.BUILDER_PARAM); - isLinkIntrinsic ||= isDecoratorIntrinsicAnnotation(anno, DecoratorIntrinsicNames.LINK); + isLink ||= isDecoratorAnnotation(anno, DecoratorNames.LINK); }); - return factory.updateSpecificProperties(prop, key, value, { isBuilderParam, isLinkIntrinsic }, declInfo); + return factory.updateSpecificProperties(prop, key, value, { isBuilderParam, isLink, isNotBacking }, declInfo); } static updateSpecificProperties( @@ -451,7 +452,8 @@ export class factory { addMemoAnnotation(value); newProperty = prop; } else if ( - propertyInfo.isLinkIntrinsic && + propertyInfo.isLink && + propertyInfo.isNotBacking && arkts.isMemberExpression(value) && arkts.isThisExpression(value.object) && arkts.isIdentifier(value.property) @@ -692,11 +694,9 @@ export class factory { const alternate = !!statement.alternate ? this.updateIfElseContentBodyInBuilderLambda(statement.alternate, shouldWrap, stopAtBuilderLambda) : statement.alternate; - const consequence = this.updateIfElseContentBodyInBuilderLambda( - statement.consequent!, - shouldWrap, - stopAtBuilderLambda - ); + const consequence = !!statement.consequent + ? this.updateIfElseContentBodyInBuilderLambda(statement.consequent, shouldWrap, stopAtBuilderLambda) + : undefined; const newStatement = arkts.factory.updateIfStatement(statement, statement.test, consequence!, alternate); return !shouldWrap || checkIsWithInIfConditionScope(statement) ? newStatement @@ -801,7 +801,7 @@ export class factory { const newCall = arkts.factory.createCallExpression(arkts.factory.createIdentifier(condition), [ contentArg, ], undefined, false, false); - arkts.MemoNodeCache.getInstance().collect(newCall); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newCall); ImportCollector.getInstance().collectSource(condition, ARKUI_BUILDER_SOURCE_NAME); ImportCollector.getInstance().collectImport(condition); return arkts.factory.createExpressionStatement(newCall); @@ -828,7 +828,9 @@ export class factory { this.transformBuilderLambda(statement.expression) ); } - if (!BuilderFactory.needIfConversion) return statement; + if (!BuilderFactory.needIfConversion) { + return statement; + } if (arkts.isIfStatement(statement)) { return this.updateIfElseContentBodyInBuilderLambda(statement, hasBuilder, stopAtBuilderLambda); } @@ -912,7 +914,7 @@ export class factory { replaceBuilderLambdaDeclMethodName(nameNode?.name), [] ); - arkts.MemoNodeCache.getInstance().collect(newNode); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); return newNode; } @@ -1004,10 +1006,10 @@ export class factory { }); } lambdaBodyInfo.lambdaBody = lambdaBody; - const args: (arkts.Expression | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBodyInfo, declInfo); const newNode = arkts.factory.updateCallExpression(node, replace, filterDefined(args), leaf.typeParams, node.isOptional, node.hasTrailingComma, node.trailingBlock); - arkts.MemoNodeCache.getInstance().collect(newNode); + InitialBuilderLambdaBodyCache.getInstance().updateAll().reset(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newNode); return newNode; } @@ -1038,7 +1040,6 @@ export class factory { undefined, [annotation(DecoratorNames.BUILDER)] ); - arkts.MemoNodeCache.getInstance().collect(param); const method = UIFactory.createMethodDefinition({ key: key.clone(), kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_NONE, @@ -1052,7 +1053,8 @@ export class factory { }, modifiers, }); - arkts.MemoNodeCache.getInstance().collect(method); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(param); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method); return method; } @@ -1249,9 +1251,9 @@ export class factory { }, modifiers, }); - addMemoAnnotation(newMethod.function!); - factory.globalMemoPluginContext?.registerAdditionalDeclarationRedirect(record.functionPeer, newMethod.function.peer); - arkts.MemoNodeCache.getInstance().collect(newMethod); + addMemoAnnotation(newMethod.function); + factory.globalMemoPluginContext?.registerAdditionalDeclarationRedirect(record.functionPeer, newMethod.function.peer) + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newMethod); return newMethod; } @@ -1349,22 +1351,27 @@ export class factory { ]) ) ); - const newMapArg = arkts.factory.createArrayExpression( - entries.map(([k, v]) => { - const name = k.name; - const key = arkts.factory.createStringLiteral(name); - const value = this.prepareBuilderParameterPropertyValue(v); - const arrowFunc = arkts.factory.createArrowFunctionExpression( - UIFactory.createScriptFunction({ - body: arkts.factory.createBlockStatement([arkts.factory.createReturnStatement(value)]), - returnTypeAnnotation: UIFactory.createTypeReferenceFromString(TypeNames.ANY), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + let newMapArgs: arkts.Expression[] = []; + if (entries.length > 0) { + newMapArgs.push( + arkts.factory.createArrayExpression( + entries.map(([k, v]) => { + const name = k.name; + const key = arkts.factory.createStringLiteral(name); + const value = this.prepareBuilderParameterPropertyValue(v); + const arrowFunc = arkts.factory.createArrowFunctionExpression( + UIFactory.createScriptFunction({ + body: arkts.factory.createBlockStatement([arkts.factory.createReturnStatement(value)]), + returnTypeAnnotation: UIFactory.createTypeReferenceFromString(TypeNames.ANY), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + }) + ); + return arkts.factory.createArrayExpression([key, arrowFunc]); }) - ); - return arkts.factory.createArrayExpression([key, arrowFunc]); - }) - ); - return arkts.factory.createETSNewClassInstanceExpression(newMapName, [newMapArg]); + ) + ); + } + return arkts.factory.createETSNewClassInstanceExpression(newMapName, newMapArgs); } /** diff --git a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index e4b6cd21c1a259c7a99ff7c9ee7faf3d66bbdb90..58fc1a6af019eeee2b0fe0c6b128f5269d82362d 100644 --- a/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -14,21 +14,20 @@ */ import * as arkts from '@koalaui/libarkts'; -import { isAnnotation, matchPrefix } from '../../common/arkts-utils'; -import { BuilderLambdaNames, expectNameInTypeReference, isCustomComponentAnnotation } from '../utils'; +import { coerceToAstNode, expectNameInTypeReference, isAnnotation, matchPrefix } from '../../common/arkts-utils'; +import { BuilderLambdaNames, isCustomComponentAnnotation } from '../utils'; import { DeclarationCollector } from '../../common/declaration-collector'; import { - ARKUI_FOREACH_SOURCE_NAME, ARKUI_IMPORT_PREFIX_NAMES, + DecoratorNames, Dollars, InnerComponentAttributes, - InnerComponentNames, StructDecoratorNames, } from '../../common/predefines'; import { ImportCollector } from '../../common/import-collector'; -import { hasMemoAnnotation } from '../../collectors/memo-collectors/utils'; import { AstNodePointer } from '../../common/safe-types'; -import { MetaDataCollector } from '../../common/metadata-collector'; +import { CallInfo, CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { checkIsBuilderLambdaFunctionCallFromInfo } from '../../collectors/ui-collectors/utils'; export type BuilderLambdaDeclInfo = { name: string; @@ -38,11 +37,13 @@ export type BuilderLambdaDeclInfo = { moduleName: string; hasReceiver?: boolean; isFromCommonMethod?: boolean; + isTrailingCall?: boolean; }; export type BuilderLambdaStyleBodyInfo = { lambdaBody: arkts.Identifier | arkts.CallExpression | undefined; initCallPtr: AstNodePointer | undefined; + structPropertyInfos?: CustomComponentInterfacePropertyInfo[]; }; export type BuilderLambdaAstNode = arkts.ScriptFunction | arkts.ETSParameterExpression | arkts.FunctionDeclaration; @@ -75,21 +76,10 @@ export type BuilderLambdaChainingCallArgInfo = { export type OptionsPropertyInfo = { isBuilderParam: boolean; - isLinkIntrinsic: boolean; + isLink: boolean; + isNotBacking: boolean; }; -/** - * Determine whether the node is ForEach method declaration or call expression. - * - * @param node method definition node. - * @param sourceName external source name. - */ -export function isForEach(name: string | undefined, sourceName?: string): boolean { - const externalSourceName = sourceName ?? MetaDataCollector.getInstance().externalSourceName; - return (name === InnerComponentNames.FOR_EACH || name == InnerComponentNames.FOR_EACH_IMPL) - && externalSourceName === ARKUI_FOREACH_SOURCE_NAME; -} - export function buildSecondLastArgInfo( type: arkts.Identifier | undefined, isFunctionCall: boolean @@ -97,7 +87,7 @@ export function buildSecondLastArgInfo( let isReusable: boolean | undefined; let reuseId: string | undefined; if (!isFunctionCall && !!type) { - const customComponentDecl = arkts.getDecl(type); + const customComponentDecl = arkts.getPeerIdentifierDecl(type.peer); isReusable = !!customComponentDecl && arkts.isClassDefinition(customComponentDecl) && @@ -155,7 +145,7 @@ export function isFunctionWithReceiver(node: arkts.MethodDefinition): boolean { * @param node identifier node */ export function isFunctionWithReceiverCall(node: arkts.Identifier): boolean { - const decl: arkts.AstNode | undefined = arkts.getDecl(node); + const decl: arkts.AstNode | undefined = arkts.getPeerIdentifierDecl(node.peer); if (decl && arkts.isMethodDefinition(decl)) { return isFunctionWithReceiver(decl); } @@ -175,6 +165,13 @@ export function isStyleChainedCall(node: arkts.CallExpression): boolean { ); } +/** + * Determine whether it is a style chained callee. + */ +export function isStyleChainedCallee(callee: arkts.AstNode): callee is arkts.MemberExpression { + return arkts.isMemberExpression(callee) && arkts.isCallExpression(callee.object); +} + /** * Determine whether it is a style function with receiver call. * @@ -189,6 +186,20 @@ export function isStyleWithReceiverCall(node: arkts.CallExpression): boolean { ); } +/** + * Determine whether it is a style function with receiver callee. + */ +export function isStyleWithReceiverCallee( + node: arkts.CallExpression, + callee: arkts.AstNode, + isReceiver?: boolean +): boolean { + if (node.arguments.length === 0) { + return false; + } + return !!isReceiver && arkts.isIdentifier(callee) && arkts.isCallExpression(node.arguments.at(0)!); +} + /** * replace $_instantiate with _instantiateImpl. * @@ -354,7 +365,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; } @@ -382,7 +393,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; } @@ -401,12 +412,42 @@ export function findBuilderLambdaDeclInfo(decl: arkts.AstNode | undefined): Buil return { name, isFunctionCall, params, returnType, moduleName, hasReceiver, isFromCommonMethod }; } +export function collectDeclInfoFromInfo(node: arkts.AstNode, metadata: CallInfo): BuilderLambdaDeclInfo | undefined { + if (!metadata?.isDeclFromMethod && !metadata?.isDeclFromFunction) { + return undefined; + } + + const name: string = metadata.declName!; + const rootCallee: arkts.CallExpression = coerceToAstNode(node); + const decl: arkts.MethodDefinition = coerceToAstNode(findRootCalleeDecl(rootCallee)!); + const func: arkts.ScriptFunction = decl.function; + const originType = func.returnTypeAnnotation; + const params: arkts.Expression[] = func.params.map((p) => p.clone()); + const returnType: arkts.TypeNode | undefined = originType?.clone(); + const isFunctionCall: boolean = !metadata.structDeclInfo; + const moduleName: string = metadata.moduleName!; + const isTrailingCall: boolean | undefined = metadata.isTrailingCall; + const hasReceiver: boolean | undefined = metadata.hasReceiver; + const isFromCommonMethod: boolean = isFunctionCall && findComponentAttributeFromCommonMethod(originType); + return { name, params, returnType, isFunctionCall, moduleName, isTrailingCall, hasReceiver, isFromCommonMethod }; +} + +export function findRootCalleeDecl(rootCall: arkts.CallExpression | arkts.Identifier): arkts.AstNode | undefined { + let decl: arkts.AstNode | undefined; + if (arkts.isIdentifier(rootCall)) { + decl = arkts.getPeerIdentifierDecl(rootCall.peer); + } else { + decl = arkts.getDecl(rootCall.callee!); + } + return decl; +} + export function findComponentAttributeFromCommonMethod(attrType: arkts.TypeNode | undefined): boolean { const nameNode = expectNameInTypeReference(attrType); if (!nameNode) { return false; } - const decl = arkts.getDecl(nameNode); + const decl = arkts.getPeerIdentifierDecl(nameNode.peer); return findCommonMethodInterfaceInExtends(decl); } @@ -424,7 +465,7 @@ export function findCommonMethodInterfaceInExtends(interfaceNode: arkts.AstNode } return extendNodes.some((node) => { const name = expectNameInTypeReference(node.expr); - const decl = !!name ? arkts.getDecl(name) : undefined; + const decl = !!name ? arkts.getPeerIdentifierDecl(name.peer) : undefined; return findCommonMethodInterfaceInExtends(decl); }); } @@ -514,11 +555,11 @@ export function isDoubleDollarCall( return false; } if (!ignoreDecl) { - const decl = arkts.getDecl(expr); + const decl = arkts.getPeerIdentifierDecl(expr.peer); 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; } @@ -585,7 +626,7 @@ export function getElementTypeFromArray(arrayType: arkts.TypeNode): arkts.TypeNo function findAttributeNameFromTypeName(typeName: arkts.Identifier | undefined): string | undefined { if (!typeName) { - return; + return undefined; } const regex: RegExp = /(?\w+Attribute)(?:<.*>)?$/; const match: RegExpExecArray | null = regex.exec(typeName.name); @@ -626,7 +667,7 @@ function findClassInstanceFromType( if (!ident || !arkts.isIdentifier(ident)) { return undefined; } - const decl = arkts.getDecl(ident); + const decl = arkts.getPeerIdentifierDecl(ident.peer); if (!decl) { return undefined; } @@ -680,60 +721,6 @@ export function flatObjectExpressionToEntries( return entries; } -function checkIsTrailingLambdaType(typeNode: arkts.AstNode | undefined): boolean { - if (!typeNode) { - return false; - } - if (arkts.isETSFunctionType(typeNode)) { - return typeNode.params.length === 0 && !!typeNode.returnType && typeNode.returnType.dumpSrc() === 'void'; - } - if (arkts.isETSUnionType(typeNode)) { - let hasTrailingLambdaType: boolean = false; - let hasOtherNonUndefinedTypes: boolean = false; - for (const t of typeNode.types) { - if ((hasTrailingLambdaType && !arkts.isETSUndefinedType(t)) || hasOtherNonUndefinedTypes) { - hasOtherNonUndefinedTypes = true; - break; - } - hasTrailingLambdaType ||= checkIsTrailingLambdaType(t); - hasOtherNonUndefinedTypes ||= !hasTrailingLambdaType && !arkts.isETSUndefinedType(t); - } - return hasTrailingLambdaType && !hasOtherNonUndefinedTypes; - } - if (arkts.isETSTypeReference(typeNode)) { - const name = expectNameInTypeReference(typeNode); - const decl = !!name ? arkts.getDecl(name) : undefined; - return checkIsTrailingLambdaType(decl); - } - if (arkts.isTSTypeAliasDeclaration(typeNode)) { - return checkIsTrailingLambdaType(typeNode.typeAnnotation) - } - return false; -} - -/** - * check whether the last parameter is trailing lambda in components. - */ -export function checkIsTrailingLambdaInLastParam(params: readonly arkts.Expression[]): boolean { - if (params.length === 0) { - return false; - } - const lastParam = params.at(params.length - 1)! as arkts.ETSParameterExpression; - // stub for new SDK with "CustomBuilder" parameter type instead of "@memo () => void" - // return hasMemoAnnotation(lastParam) && checkIsTrailingLambdaType(lastParam.typeAnnotation); - return checkIsTrailingLambdaType(lastParam.typeAnnotation); -} - -/** - * remove any parameters except possible last trailing lambda parameter in components. - */ -export function filterParamsExpectTrailingLambda(params: readonly arkts.Expression[]): readonly arkts.Expression[] { - if (checkIsTrailingLambdaInLastParam(params)) { - return [params.at(params.length - 1)!]; - } - return []; -} - /** * find `XXXAttribute` interface name from the component's attribute interface. */ @@ -744,7 +731,6 @@ export function findComponentAttributeInInterface(node: arkts.TSInterfaceDeclara return findAttributeNameFromTypeName(node.id); } - /** * get set method name for components. */ diff --git a/ui2abc/arkui-plugins/ui-plugins/checked-cache-factory.ts b/ui2abc/arkui-plugins/ui-plugins/checked-cache-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae4f0296c91c717dbdfbd5cdc853cecbf2728113 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/checked-cache-factory.ts @@ -0,0 +1,557 @@ +/* + * 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 { + ArrowFunctionExpressionRecordInfo, + CallExpressionRecordInfo, + CallInfo, + ClassDeclarationRecordInfo, + ClassPropertyRecordInfo, + CustomComponentInfo, + CustomComponentInterfaceInfo, + CustomComponentInterfacePropertyInfo, + ETSNewClassInstanceExpressionRecordInfo, + ETSParameterExpressionRecordInfo, + FunctionInfo, + MethodDefinitionRecordInfo, + NormalClassInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + NormalInterfaceInfo, + NormalInterfacePropertyInfo, + ParameterInfo, + PropertyRecordInfo, + RecordInfo, + StructMethodInfo, + StructPropertyInfo, + TSInterfaceDeclarationRecordInfo, +} from '../collectors/ui-collectors/records'; +import { + checkIsAnimatableExtendMethodFromInfo, + checkIsBuilderFromInfo, + checkIsBuilderLambdaFromInfo, + checkIsBuilderLambdaMethodDeclFromInfo, + checkIsCallFromLegacyBuilderFromInfo, + checkIsCommonMethodInterfaceFromInfo, + checkIsComponentAttributeInterfaceFromInfo, + checkIsComputedMethodFromInfo, + checkIsCustomComponentClassFromInfo, + checkIsCustomComponentDeclaredClassFromInfo, + checkIsCustomComponentFromInfo, + checkIsCustomDialogControllerBuilderOptionsFromInfo, + checkIsDialogControllerNewInstanceFromInfo, + checkIsETSGlobalClassFromInfo, + checkIsFunctionMethodDeclFromInfo, + checkIsGlobalFunctionFromInfo, + checkIsInteropComponentCallFromInfo, + checkIsMonitorMethodFromInfo, + checkIsNormalClassHasTrackProperty, + checkIsNormalClassMethodFromInfo, + checkIsNormalClassPropertyFromInfo, + checkIsNormalInterfacePropertyFromInfo, + checkIsObservedClassFromInfo, + checkIsObservedImplementsMethod, + checkIsObservedV2ImplementsMethod, + checkIsResourceFromInfo, + checkIsStructInterfacePropertyFromInfo, + checkIsStructMethodFromInfo, + checkIsStructPropertyFromInfo, + getGetterSetterTypeFromInfo, +} from '../collectors/ui-collectors/utils'; +import { coerceToAstNode } from '../collectors/ui-collectors/validators/utils'; +import { getPerfName } from '../common/debug'; +import { ARKUI_BUILDER_SOURCE_NAME, ARKUI_INTEROP_SOURCE_NAME, EntryWrapperNames, NodeCacheNames } from '../common/predefines'; +import { ImportCollector } from '../common/import-collector'; +import { factory as UIFactory } from './ui-factory'; +import { CacheFactory as StructCacheFactory } from './struct-translators/cache-factory'; +import { factory as StructFactory } from './struct-translators/factory'; +import { CacheFactory as PropertyCacheFactory } from './property-translators/cache-factory'; +import { factory as PropertyFactory } from './property-translators/factory'; +import { CacheFactory as BuilderLambdaCacheFactory } from './builder-lambda-translators/cache-factory'; +import { factory as BuilderLambdaFactory } from './builder-lambda-translators/factory'; +import { BuilderFactory } from './builder-lambda-translators/builder-factory'; +import { CacheFactory as EntryCacheFactory } from './entry-translators/cache-factory'; +import { factory as EntryFactory } from './entry-translators/factory'; +import { + InterfacePropertyCachedTranslator, + PropertyCachedTranslator, +} from './property-translators/base'; +import { + classifyObservedClassPropertyFromInfo, + classifyPropertyFromInfo, + classifyPropertyInInterfaceFromInfo, +} from './property-translators'; +import { PropertyRewriteCache } from './property-translators/cache/propertyRewriteCache'; +import { ConditionScopeFactory } from './condition-scope-translators/condition-scope-factory'; +import { generateBuilderCompatible, insertCompatibleImport } from './interop/builder-interop'; +import { insertInteropComponentImports } from './interop/utils'; +import { generateArkUICompatible } from './interop/interop'; +import { StructType } from './utils'; + +export class RewriteFactory { + /** + * @internal + */ + static rewriteCustomComponentDecl( + node: arkts.ClassDeclaration, + metadata: CustomComponentInfo + ): arkts.ClassDeclaration { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 8, 2, 1], 'custom component class checked CUSTOM_COMPONENT_DECL') + ); + const res = StructCacheFactory.tranformClassMembersFromInfo(node, metadata, StructType.CUSTOM_COMPONENT_DECL); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 8, 2, 1], 'custom component class checked CUSTOM_COMPONENT_DECL') + ); + return res; + } + + /** + * @internal + */ + static rewriteStruct(node: arkts.ClassDeclaration, metadata: CustomComponentInfo): arkts.ClassDeclaration { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 8, 1, 1], 'custom component class checked STRUCT') + ); + const res = StructCacheFactory.tranformClassMembersFromInfo(node, metadata, StructType.STRUCT); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 8, 1, 1], 'custom component class checked STRUCT') + ); + return res; + } + + /** + * @internal + */ + static rewriteCustomComponentClass( + node: arkts.ClassDeclaration, + metadata: CustomComponentInfo + ): arkts.ClassDeclaration { + if (checkIsCustomComponentFromInfo(metadata)) { + // Struct + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 8, 1], 'rewriteStruct')); + const res = RewriteFactory.rewriteStruct(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 8, 1], 'rewriteStruct')); + return res; + } + if (checkIsCustomComponentDeclaredClassFromInfo(metadata)) { + // CustomComponent/CustomComponentV2/CustomDialog + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 8, 2], 'rewriteCustomComponentDecl') + ); + const res = RewriteFactory.rewriteCustomComponentDecl(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 8, 2], 'rewriteCustomComponentDecl')); + return res; + } + return node; + } + + /** + * @internal + */ + static rewriteETSGlobalClass(node: arkts.ClassDeclaration, metadata: NormalClassInfo): arkts.ClassDeclaration { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 9, 1, 1], 'EtsGlobalClass')); + const res = StructCacheFactory.transformETSGlobalClassFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 9, 1, 1], 'EtsGlobalClass')); + return res; + } + + /** + * @internal + */ + static rewriteObservedClass(node: arkts.ClassDeclaration, metadata: NormalClassInfo): arkts.ClassDeclaration { + return StructCacheFactory.transformObservedClassFromInfo(node, metadata); + } + + /** + * @internal + */ + static rewriteNormalClass(node: arkts.ClassDeclaration, metadata: NormalClassInfo): arkts.ClassDeclaration { + if (checkIsETSGlobalClassFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 9, 1], 'rewriteETSGlobalClass')); + const res = RewriteFactory.rewriteETSGlobalClass(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 9, 1], 'rewriteETSGlobalClass')); + return res; + } + if (checkIsObservedClassFromInfo(metadata) || checkIsNormalClassHasTrackProperty(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 9, 2], 'rewriteObservedClass')); + const res = RewriteFactory.rewriteObservedClass(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 9, 2], 'rewriteObservedClass')); + return res; + } + return node; + } + + /** + * @internal + */ + static rewriteStructProperty(node: arkts.ClassProperty, metadata: StructPropertyInfo): arkts.ClassProperty { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 1, 1], 'classifyPropertyFromInfo')); + const propertyTranslator: PropertyCachedTranslator | undefined = classifyPropertyFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 1, 1], 'classifyPropertyFromInfo')); + if (!propertyTranslator) { + return node; + } + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 1, 2], 'rewriteMember')); + const newNodes: arkts.AstNode[] = propertyTranslator.translateMember(); + PropertyRewriteCache.getInstance().collectRewriteNodes(node.peer, newNodes); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 1, 2], 'rewriteMember')); + return node; + } + + /** + * @internal + */ + static rewriteNormalClassProperty( + node: arkts.ClassProperty, + metadata: NormalClassPropertyInfo + ): arkts.ClassProperty { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 1, 1], 'classifyPropertyFromInfo')); + const propertyTranslator = classifyObservedClassPropertyFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 1, 1], 'classifyPropertyFromInfo')); + if (!propertyTranslator) { + return node; + } + const newNodes: arkts.AstNode[] = propertyTranslator.translateMember(); + PropertyRewriteCache.getInstance().collectRewriteNodes(node.peer, newNodes); + return node; + } + + /** + * @internal + */ + static rewriteStructMethod(node: arkts.MethodDefinition, metadata: StructMethodInfo): arkts.MethodDefinition { + // rewrite `$_instantiate` in CustomComponent/CustomComponentV2/CustomDialog decl class + if (checkIsBuilderLambdaMethodDeclFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 3, 1], '@ComponentBuilder Method $_instantiate') + ); + const res = BuilderLambdaCacheFactory.transformBuilderLambdaMethodDeclFromInfo(node, metadata, true); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 3, 1], '@ComponentBuilder Method $_instantiate') + ); + return res; + } + if (checkIsComputedMethodFromInfo(metadata)) { + return PropertyCacheFactory.rewriteComputedMethodFromInfo(node, metadata); + } + if (checkIsMonitorMethodFromInfo(metadata)) { + return PropertyCacheFactory.rewriteMonitorMethodFromInfo(node, metadata); + } + return StructCacheFactory.transformNonPropertyMembersInClassFromInfo(node, metadata); + } + + /** + * @internal + */ + static rewriteStructInterfaceProperty( + node: arkts.MethodDefinition, + metadata: CustomComponentInterfacePropertyInfo + ): arkts.MethodDefinition { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 6, 1], 'classifyPropertyInInterfaceFromInfo') + ); + const interfacePropertyTranslator: InterfacePropertyCachedTranslator | undefined = + classifyPropertyInInterfaceFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 6, 1], 'classifyPropertyInInterfaceFromInfo') + ); + if (!interfacePropertyTranslator) { + return node; + } + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 6, 2], 'translateProperty')); + const res = interfacePropertyTranslator.translateProperty(); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 6, 2], 'translateProperty')); + return res; + } + + /** + * @internal + */ + static rewriteNormalClassMethod( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo + ): arkts.MethodDefinition { + if (!metadata.classInfo) { + return node; + } + // Entry + if (metadata.classInfo?.name === EntryWrapperNames.WRAPPER_CLASS_NAME) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 5, 1], 'EntryWrapperClass')); + EntryCacheFactory.addMemoToEntryWrapperClassMethodFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 5, 1], 'EntryWrapperClass')); + return node; + } + if (checkIsComputedMethodFromInfo(metadata)) { + return PropertyCacheFactory.rewriteComputedMethodFromInfo(node, metadata); + } + if (checkIsMonitorMethodFromInfo(metadata)) { + return PropertyCacheFactory.rewriteMonitorMethodFromInfo(node, metadata); + } + if (checkIsObservedImplementsMethod(metadata)) { + const getSetTypes = getGetterSetterTypeFromInfo(metadata); + const res = PropertyCacheFactory.transformObservedImplementsMethodFromInfo(node, metadata, getSetTypes); + return res; + } + if (checkIsObservedV2ImplementsMethod(metadata)) { + const getSetTypes = getGetterSetterTypeFromInfo(metadata); + const res = PropertyCacheFactory.transformObservedV2ImplementsMethodFromInfo(node, metadata, getSetTypes); + return res; + } + return node; + } + + /** + * @internal + */ + static rewriteNormalInterfaceProperty( + node: arkts.MethodDefinition, + metadata: NormalInterfacePropertyInfo + ): arkts.MethodDefinition { + if (checkIsCustomDialogControllerBuilderOptionsFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 5, 1], 'updateBuilderType')); + const res = StructCacheFactory.updateBuilderType(node); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 5, 1], 'updateBuilderType')); + return res; + } + return node; + } + + /** + * @internal + */ + static rewriteGlobalFunction(node: arkts.MethodDefinition, metadata: FunctionInfo): arkts.MethodDefinition { + // rewrite `@ComponentBuilder` declared method. + if (checkIsBuilderLambdaMethodDeclFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 4, 1], '@ComponentBuilder Method Inner Component') + ); + const res = BuilderLambdaCacheFactory.transformBuilderLambdaMethodDeclFromInfo(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 4, 1], '@ComponentBuilder Method Inner Component') + ); + return res; + } + if (checkIsAnimatableExtendMethodFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 4, 2], '@AnimatableExtend Global Function') + ); + const res = StructCacheFactory.transformAnimatableExtendMethod(node, metadata); + arkts.Performance.getInstance().stopDetailedEvent( + getPerfName([1, 1, 4, 2], '@AnimatableExtend Global Function') + ); + return res; + } + return node; + } + + static rewriteClassDeclaration( + node: T, + metadata: ClassDeclarationRecordInfo + ): arkts.ClassDeclaration { + const _node = coerceToAstNode(node); + if (checkIsCustomComponentClassFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 8], 'rewriteCustomComponentClass')); + const res = RewriteFactory.rewriteCustomComponentClass(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 8], 'rewriteCustomComponentClass')); + return res; + } + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 9], 'rewriteNormalClass')); + const res = RewriteFactory.rewriteNormalClass(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 9], 'rewriteNormalClass')); + return res; + } + + static rewriteMethodDefinition( + node: T, + metadata: MethodDefinitionRecordInfo + ): arkts.MethodDefinition { + let _node = coerceToAstNode(node); + if (checkIsStructMethodFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 3], 'rewriteStructMethod')); + _node = RewriteFactory.rewriteStructMethod(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 3], 'rewriteStructMethod')); + } else if (checkIsGlobalFunctionFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 4], 'rewriteGlobalFunction')); + _node = RewriteFactory.rewriteGlobalFunction(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 4], 'rewriteGlobalFunction')); + } else if (checkIsNormalClassMethodFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 5], 'rewriteNormalClassMethod')); + _node = RewriteFactory.rewriteNormalClassMethod(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 5], 'rewriteNormalClassMethod')); + } else if (checkIsStructInterfacePropertyFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 6], 'rewriteStructInterfaceProperty') + ); + _node = RewriteFactory.rewriteStructInterfaceProperty(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 6], 'rewriteStructInterfaceProperty')); + } else if (checkIsNormalInterfacePropertyFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent( + getPerfName([1, 1, 7], 'rewriteNormalInterfaceProperty') + ); + _node = RewriteFactory.rewriteNormalInterfaceProperty(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 7], 'rewriteNormalInterfaceProperty')); + } + if (checkIsBuilderFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 3], 'rewriteBuilderMethod')); + const res = ConditionScopeFactory.rewriteBuilderMethod(_node); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 3], 'rewriteBuilderMethod')); + return res; + } + return _node; + } + + static rewriteClassProperty( + node: T, + metadata: ClassPropertyRecordInfo + ): arkts.ClassProperty { + let _node = coerceToAstNode(node); + if (checkIsStructPropertyFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 1], 'rewriteStructProperty')); + _node = RewriteFactory.rewriteStructProperty(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 1], 'rewriteStructProperty')); + } + if (checkIsNormalClassPropertyFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 2], 'rewriteNormalClassProperty')); + _node = RewriteFactory.rewriteNormalClassProperty(_node, metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 2], 'rewriteNormalClassProperty')); + } + if (checkIsBuilderFromInfo(metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 3], 'rewriteBuilderClassProperty')); + const res = ConditionScopeFactory.rewriteBuilderClassProperty(_node); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 3], 'rewriteBuilderClassProperty')); + return res; + } + return _node; + } + + static rewriteCallExpression( + node: T, + metadata: RecordInfo + ): arkts.CallExpression { + const _node = coerceToAstNode(node); + const _metadata = metadata as CallInfo; + if (checkIsCallFromLegacyBuilderFromInfo(_metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 0], 'Legacy Builder call')); + insertCompatibleImport(); + const res = generateBuilderCompatible(_node, _metadata.callName!); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 0], 'Legacy Builder call')); + return res; + } + if (checkIsInteropComponentCallFromInfo(_metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 1], 'Legacy Struct call')); + insertInteropComponentImports(); + const res = generateArkUICompatible(_node, !!_metadata.isDeclFromFunction); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 1], 'Legacy Struct call')); + return res; + } + if (checkIsBuilderLambdaFromInfo(_metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 2], '@ComponentBuilder call')); + const res = BuilderLambdaCacheFactory.transformBuilderLambdaFromInfo(_node, _metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 2], '@ComponentBuilder call')); + return res; + } + if (checkIsResourceFromInfo(_metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 3], '$r and $rawfile')); + const res = StructCacheFactory.transformResourceFromInfo(_node, _metadata); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 3], '$r and $rawfile')); + return res; + } + if (checkIsBuilderFromInfo(_metadata)) { + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 1, 4], 'Builder call')); + const res = BuilderFactory.rewriteBuilderCall(_node); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 1, 4], 'Builder call')); + return res; + } + return _node; + } + + static rewriteETSParameterExpression( + node: T, + metadata: RecordInfo + ): arkts.ETSParameterExpression { + const _node = coerceToAstNode(node); + const _metadata = metadata as ETSParameterExpressionRecordInfo; + if (checkIsBuilderFromInfo(_metadata)) { + return ConditionScopeFactory.rewriteBuilderParameter(_node); + } + return _node; + } + + static rewriteArrowFunctionExpression( + node: T, + metadata: RecordInfo + ): arkts.ArrowFunctionExpression { + const _node = coerceToAstNode(node); + const _metadata = metadata as ArrowFunctionExpressionRecordInfo; + if (checkIsBuilderFromInfo(_metadata)) { + return ConditionScopeFactory.rewriteBuilderArrowFunction(_node); + } + return _node; + } + + static rewriteProperty(node: T, metadata: RecordInfo): arkts.Property { + const _node = coerceToAstNode(node); + const _metadata = metadata as PropertyRecordInfo; + if (checkIsBuilderFromInfo(_metadata)) { + return ConditionScopeFactory.rewriteBuilderProperty(_node); + } + return _node; + } + + static rewriteInterface( + node: T, + metadata: TSInterfaceDeclarationRecordInfo + ): arkts.TSInterfaceDeclaration { + const _node = coerceToAstNode(node); + if (checkIsCommonMethodInterfaceFromInfo(metadata)) { + return StructFactory.modifyExternalComponentCommon(_node); + } + if (checkIsComponentAttributeInterfaceFromInfo(metadata)) { + return StructCacheFactory.extendInnerComponentAttributeInterface(_node, metadata); + } + return _node; + } + + static rewriteETSNewClassInstanceExpression( + node: T, + metadata: RecordInfo + ): arkts.ETSNewClassInstanceExpression { + const _node = coerceToAstNode(node); + const _metadata = metadata as ETSNewClassInstanceExpressionRecordInfo; + if (checkIsDialogControllerNewInstanceFromInfo(_metadata)) { + return StructFactory.transformCustomDialogController(_node) as arkts.ETSNewClassInstanceExpression; + } + return _node; + } +} + +type RewriteFunction = (node: T, metadata: RecordInfo) => arkts.AstNode; + +export const rewriteByType = new Map([ + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_DECLARATION, RewriteFactory.rewriteClassDeclaration], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CLASS_PROPERTY, RewriteFactory.rewriteClassProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_METHOD_DEFINITION, RewriteFactory.rewriteMethodDefinition], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_CALL_EXPRESSION, RewriteFactory.rewriteCallExpression], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_PARAMETER_EXPRESSION, RewriteFactory.rewriteETSParameterExpression], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION, RewriteFactory.rewriteArrowFunctionExpression], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_PROPERTY, RewriteFactory.rewriteProperty], + [arkts.Es2pandaAstNodeType.AST_NODE_TYPE_TS_INTERFACE_DECLARATION, RewriteFactory.rewriteInterface], + [ + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_ETS_NEW_CLASS_INSTANCE_EXPRESSION, + RewriteFactory.rewriteETSNewClassInstanceExpression, + ], +]); diff --git a/ui2abc/arkui-plugins/ui-plugins/checked-transformer.ts b/ui2abc/arkui-plugins/ui-plugins/checked-transformer.ts index f4691475bd4b95cf8ad1e88a93a7965382dd94fb..6e9ab1f38b295f3e08b28982717fa99e18b652c7 100644 --- a/ui2abc/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/ui2abc/arkui-plugins/ui-plugins/checked-transformer.ts @@ -14,12 +14,12 @@ */ import * as arkts from '@koalaui/libarkts'; -import { PluginContext, ProjectConfig } from '../common/plugin-context'; +import { PluginContext, ProjectConfig, ResourceInfo } from '../common/plugin-context'; import { factory as structFactory } from './struct-translators/factory'; import { factory as builderLambdaFactory } from './builder-lambda-translators/factory'; import { factory as entryFactory } from './entry-translators/factory'; -import { AbstractVisitor } from '../common/abstract-visitor'; -import { isBuilderLambda, isBuilderLambdaMethod } from './builder-lambda-translators/utils'; +import { AbstractVisitor, VisitorOptions } from '../common/abstract-visitor'; +import { isBuilderLambda, isBuilderLambdaMethodDecl } from './builder-lambda-translators/utils'; import { isEntryWrapperClass } from './entry-translators/utils'; import { ImportCollector } from '../common/import-collector'; import { DeclarationCollector } from '../common/declaration-collector'; @@ -30,7 +30,6 @@ import { initResourceInfo, loadBuildJson, LoaderJson, - ResourceInfo, ScopeInfoCollection, } from './struct-translators/utils'; import { @@ -39,20 +38,31 @@ import { CustomDialogNames, isCustomComponentClass, isSpecificNewClass, + StructType, } from './utils'; import { findAndCollectMemoableNode } from '../collectors/memo-collectors/factory'; +import { NormalClassInfo, RecordInfo } from '../collectors/ui-collectors/records'; import { InteroperAbilityNames } from './interop/predefines'; -import { generateBuilderCompatible } from './interop/builder-interop'; +import { generateBuilderCompatible, insertCompatibleImport } from './interop/builder-interop'; import { builderRewriteByType } from './builder-lambda-translators/builder-factory'; import { MonitorCache } from './property-translators/cache/monitorCache'; import { ComputedCache } from './property-translators/cache/computedCache'; import { ComponentAttributeCache } from './builder-lambda-translators/cache/componentAttributeCache'; import { MetaDataCollector } from '../common/metadata-collector'; import { FileManager } from '../common/file-manager'; -import { LANGUAGE_VERSION } from '../common/predefines'; +import { LANGUAGE_VERSION, NodeCacheNames } from '../common/predefines'; +import { rewriteByType, RewriteFactory } from './checked-cache-factory'; +import { getPerfName } from '../common/debug'; +import { InnerComponentInfoCache } from './builder-lambda-translators/cache/innerComponentInfoCache'; +import { NodeCacheFactory } from '../common/node-cache'; import { GlobalMemoPluginContext, MEMO_PLUGIN_CONTEXT_PARAMETER_NAME, MemoPluginContext } from '@ohos/arkts-compiler-infra'; import { useImprovedPlugin } from '../common/use-improved-memo-plugin'; +export interface CheckedTransformerOptions extends VisitorOptions { + projectConfig?: ProjectConfig; + useCache?: boolean; +} + export class CheckedTransformer extends AbstractVisitor { private scope: ScopeInfoCollection; projectConfig: ProjectConfig | undefined; @@ -61,12 +71,16 @@ export class CheckedTransformer extends AbstractVisitor { globalMemoPluginContext?: GlobalMemoPluginContext; memoPluginContext?: MemoPluginContext; - constructor(projectConfig: ProjectConfig | undefined, context: PluginContext) { - super(); - this.projectConfig = projectConfig; + private readonly useCache: boolean = false; + + constructor(options: CheckedTransformerOptions, context: PluginContext) { + super(options); + this.projectConfig = options.projectConfig; + this.useCache = options.useCache ?? false; this.scope = { customComponents: [] }; this.aceBuildJson = loadBuildJson(this.projectConfig); this.resourceInfo = initResourceInfo(this.projectConfig, this.aceBuildJson); + MetaDataCollector.getInstance().setResourceInfo(this.resourceInfo); if (useImprovedPlugin) { this.globalMemoPluginContext = context.parameter(MEMO_PLUGIN_CONTEXT_PARAMETER_NAME)!; @@ -88,15 +102,14 @@ export class CheckedTransformer extends AbstractVisitor { MonitorCache.getInstance().reset(); ComputedCache.getInstance().reset(); ComponentAttributeCache.getInstance().reset(); - ImportCollector.getInstance().reset(); - DeclarationCollector.getInstance().reset(); - LogCollector.getInstance().reset(); + InnerComponentInfoCache.getInstance().reset(); + ImportCollector.getInstance().clearImports(); } enter(node: arkts.AstNode): void { if (arkts.isClassDeclaration(node) && !!node.definition && node.definition.body.length > 0) { const customComponentInfo = collectCustomComponentScopeInfo(node); - if (!!customComponentInfo) { + if (!!customComponentInfo && customComponentInfo.type !== StructType.INVALID_STRUCT) { this.scope.customComponents.push(customComponentInfo); } } @@ -125,7 +138,7 @@ export class CheckedTransformer extends AbstractVisitor { } const path = arkts.getProgramFromAstNode(decl).absoluteName; const fileManager = FileManager.getInstance(); - if (fileManager.getLanguageVersionByFilePath(path) !== LANGUAGE_VERSION.ARKTS_1_1) { + if (!path || fileManager.getLanguageVersionByFilePath(path) !== LANGUAGE_VERSION.ARKTS_1_1) { return false; } @@ -134,21 +147,55 @@ export class CheckedTransformer extends AbstractVisitor { return (annotation.expr as arkts.Identifier).name; }); for (const decorator of decorators) { - if (decorator === 'memo' || decorator === 'Builder') { + if (decorator === 'memo' || decorator === 'Builder' || decorator === 'Memo') { return true; } } return false; } - addcompatibleComponentImport(): void { - ImportCollector.getInstance().collectSource('compatibleComponent', 'arkui.component.interop'); - ImportCollector.getInstance().collectImport('compatibleComponent'); + private visitorWithCache(beforeChildren: arkts.AstNode): arkts.AstNode { + const _uiCache = NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI); + if (!_uiCache.shouldUpdate(beforeChildren)) { + return beforeChildren; + } + let node = this.visitEachChild(beforeChildren); + if (_uiCache.has(node)) { + const value = _uiCache.get(node)!; + if (rewriteByType.has(value.type)) { + const func = rewriteByType.get(value.type)!; + arkts.Performance.getInstance().createDetailedEvent(getPerfName([1, 0, 0], func.name)); + const newNode = func(node, value.metadata as RecordInfo); + arkts.Performance.getInstance().stopDetailedEvent(getPerfName([1, 0, 0], func.name)); + return newNode; + } + } + if (arkts.isETSModule(node) && !node.isNamespace) { + if (ImportCollector.getInstance().importInfos.length > 0) { + let imports = ImportCollector.getInstance().getImportStatements(); + node = arkts.factory.updateETSModule(node, [...imports, ...node.statements], node.ident, node.getNamespaceFlag(), node.program); + } + LogCollector.getInstance().shouldIgnoreError(this.projectConfig?.ignoreError); + LogCollector.getInstance().emitLogInfo(); + } + return node; } visitor(beforeChildren: arkts.AstNode): arkts.AstNode { + if (this.useCache) { + return this.visitorWithCache(beforeChildren); + } this.enter(beforeChildren); if (arkts.isCallExpression(beforeChildren)) { + // const decl = arkts.getDecl(beforeChildren.callee!); + // if (arkts.isIdentifier(beforeChildren.callee!) && this.isFromBuilder1_1(decl)) { + // // Builder + // insertCompatibleImport(); + // return generateBuilderCompatible(beforeChildren, beforeChildren.callee.name); + // } else if (isBuilderLambda(beforeChildren, decl)) { + // const lambda = builderLambdaFactory.transformBuilderLambda(beforeChildren); + // return this.visitEachChild(lambda); + // } if (!useImprovedPlugin || !beforeChildren.callee?.dumpSrc().endsWith('Impl')) { const decl = arkts.getDecl(beforeChildren.callee!); if (isBuilderLambda(beforeChildren, decl)) { @@ -156,7 +203,7 @@ export class CheckedTransformer extends AbstractVisitor { return this.visitEachChild(lambda); } } - } else if (arkts.isMethodDefinition(beforeChildren) && isBuilderLambdaMethod(beforeChildren)) { + } else if (arkts.isMethodDefinition(beforeChildren) && isBuilderLambdaMethodDecl(beforeChildren)) { const lambda = builderLambdaFactory.transformBuilderLambdaMethodDecl(beforeChildren); const result = this.visitEachChild(lambda) as arkts.MethodDefinition; // DeclarationFromIdentifier of callsite to rewrite will look at the old method definition @@ -194,7 +241,12 @@ export class CheckedTransformer extends AbstractVisitor { } else if (arkts.isClassDeclaration(node)) { return structFactory.transformNormalClass(node, this.externalSourceName); } else if (arkts.isCallExpression(node)) { - return structFactory.transformCallExpression(node, this.projectConfig, this.resourceInfo, this.scope.customComponents.length === 0); + return structFactory.transformCallExpression( + node, + this.projectConfig, + this.resourceInfo, + this.scope.customComponents.length === 0 + ); } else if (arkts.isTSInterfaceDeclaration(node)) { return structFactory.tranformInterfaceMembers(node, this.externalSourceName, this.projectConfig); } else if ( diff --git a/ui2abc/arkui-plugins/ui-plugins/component-transformer.ts b/ui2abc/arkui-plugins/ui-plugins/component-transformer.ts index 9933d0df881ed8c95181f2969b1d4d1ace204469..5347c09ce32366694683b0762d154c75cba7c20b 100644 --- a/ui2abc/arkui-plugins/ui-plugins/component-transformer.ts +++ b/ui2abc/arkui-plugins/ui-plugins/component-transformer.ts @@ -25,6 +25,9 @@ import { isCustomDialogControllerOptions, getComponentExtendsName, ComponentType, + EntryInfo, + StructType, + StructInfo, isDollarVariable, } from './utils'; import { @@ -35,28 +38,30 @@ import { collect, isDecoratorAnnotation, } from '../common/arkts-utils'; -import { ProjectConfig } from '../common/plugin-context'; -import { getEntryParams } from './entry-translators/utils'; +import { ProjectConfig, ResourceInfo } from '../common/plugin-context'; +import { getEntryParamsFromAnnotation } from './entry-translators/utils'; import { factory as entryFactory } from './entry-translators/factory'; -import { hasDecoratorName, findDecoratorInfos, DecoratorInfo } from './property-translators/utils'; +import { hasDecoratorName, findDecoratorInfos } from './property-translators/utils'; import { factory } from './ui-factory'; import { factory as propertyFactory } from './property-translators/factory'; import { factory as structFactory } from './struct-translators/factory'; import { CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - DecoratorIntrinsicNames, DecoratorNames, DECORATOR_TYPE_MAP, NavigationNames, EntryWrapperNames, - StructDecoratorNames, + LogType, RESOURCE_IMPORT_SOURCE_NAME, MEMO_IMPORT_SOURCE_NAME, + StructDecoratorNames, MEMO_SKIP_UI_IMPORT_SOURCE_NAME, } from '../common/predefines'; +import { LogCollector } from '../common/log-collector'; import { NamespaceProcessor } from './namespace-processor'; import { factory as resourceFactory } from './struct-translators/factory'; -import { isResourceNode, LoaderJson, ResourceInfo, loadBuildJson, initResourceInfo } from './struct-translators/utils' +import { isResourceNode, LoaderJson, loadBuildJson, initResourceInfo } from './struct-translators/utils' import { MemoNames } from "../collectors/memo-collectors/utils"; +import { Statement } from "@koalaui/libarkts/lib/types/generated"; export interface ComponentTransformerOptions extends VisitorOptions { arkui?: string; @@ -76,17 +81,9 @@ export interface InteropContext { export class ComponentTransformer extends AbstractVisitor { private scopeInfos: ScopeInfo[] = []; - private entryNames: string[] = []; + private entryInfos: EntryInfo[] = []; private structMembersMap: Map = new Map(); - private isCustomComponentImported: boolean = false; - private isCustomComponentV2Imported: boolean = false; - private isBaseCustomDialogImported: boolean = false; - private isEntryPointImported: boolean = false; - private isPageLifeCycleImported: boolean = false; - private isLayoutCallbackImported: boolean = false; - private shouldAddLinkIntrinsic: boolean = false; private projectConfig: ProjectConfig | undefined; - private entryRouteName: string | undefined; private componentType: ComponentType = { hasComponent: false, hasComponentV2: false, @@ -98,7 +95,6 @@ export class ComponentTransformer extends AbstractVisitor { private readonly aceBuildJson: LoaderJson; private readonly resourceInfo: ResourceInfo; private resourceCollection: Set = new Set(); - private classNode: arkts.ClassDeclaration | undefined = undefined; constructor(options?: ComponentTransformerOptions) { const _options: ComponentTransformerOptions = options ?? {}; @@ -112,89 +108,70 @@ export class ComponentTransformer extends AbstractVisitor { super.reset(); NamespaceProcessor.getInstance().reset(); this.scopeInfos = []; - this.entryNames = []; + this.entryInfos = []; this.structMembersMap = new Map(); - this.isCustomComponentImported = false; - this.isCustomComponentV2Imported = false; - this.isBaseCustomDialogImported = false; - this.isEntryPointImported = false; - this.isPageLifeCycleImported = false; - this.isLayoutCallbackImported = false; - this.shouldAddLinkIntrinsic = false; this.componentType = { hasComponent: false, hasComponentV2: false, hasCustomDialog: false, hasCustomLayout: false, }; + if (LogCollector.getInstance().logInfos.length > 0) { + LogCollector.getInstance().emitLogInfo(); + LogCollector.getInstance().reset(); + } this.resourceCollection = new Set(); - this.classNode = undefined; this.hasMemoStableImported = false; } - enter(node: arkts.AstNode) { - if (arkts.isETSStructDeclaration(node) && !!node.definition?.ident) { - const info: ScopeInfo | undefined = collectCustomComponentScopeInfo(node); - if (info) { - this.scopeInfos.push(info); - } - } - if (arkts.isClassDeclaration(node)) { - this.classNode = node; - } - if (arkts.isETSImportDeclaration(node) && !this.isCustomComponentImported) { - this.isCustomComponentImported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.COMPONENT_CLASS_NAME - ); - } - if (arkts.isETSImportDeclaration(node) && !this.isCustomComponentV2Imported) { - this.isCustomComponentV2Imported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.COMPONENT_V2_CLASS_NAME - ); - } - if (arkts.isETSImportDeclaration(node) && !this.isBaseCustomDialogImported) { - this.isBaseCustomDialogImported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.BASE_CUSTOM_DIALOG_NAME - ); - } - if (arkts.isETSImportDeclaration(node) && !this.isEntryPointImported) { - this.isEntryPointImported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - EntryWrapperNames.ENTRY_POINT_CLASS_NAME - ); + private generateStatementsForEntry(): arkts.Statement[] { + if (this.entryInfos.length === 0) { + return []; + } + this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.PAGE_LIFE_CYCLE); + if (this.entryInfos.length > 1) { + this.entryInfos.forEach((info) => { + LogCollector.getInstance().collectLogInfo({ + node: info.annotation, + message: `A page can't contain more than one '@Entry' annotation.`, + level: LogType.ERROR, + }); + }); + return []; + } + const { className, annotation, definition } = this.entryInfos.at(0)!; + const { storage, useSharedStorage, routeName } = getEntryParamsFromAnnotation(annotation); + let entryRouteName: string | undefined; + entryFactory.transformStorageParams(storage, useSharedStorage, definition); + if (routeName && routeName.value && arkts.isStringLiteral(routeName.value)) { + entryRouteName = routeName.value.str; } - if (arkts.isETSImportDeclaration(node) && !this.isPageLifeCycleImported) { - this.isPageLifeCycleImported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.PAGE_LIFE_CYCLE - ); + const updateStatements: arkts.Statement[] = []; + this.imports.push(entryFactory.createEntryPointImport(this.program)); + updateStatements.push(entryFactory.generateEntryWrapper(className)); + updateStatements.push( + entryFactory.callRegisterNamedRouter(entryRouteName, this.projectConfig, this.program?.absoluteName) + ); + this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, NavigationNames.NAVINTERFACE); + return updateStatements; + } + + enterStruct(node: arkts.ETSStructDeclaration): void { + if (!node.definition.ident) { + return; } - if (arkts.isETSImportDeclaration(node) && !this.isLayoutCallbackImported) { - this.isLayoutCallbackImported = !!findLocalImport( - node, - CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, - CustomComponentNames.LAYOUT_CALLBACKS - ); + const info: ScopeInfo | undefined = collectCustomComponentScopeInfo(node); + if (info) { + this.scopeInfos.push(info); } } - exit(node: arkts.AstNode) { - if (arkts.isETSStructDeclaration(node) || arkts.isClassDeclaration(node)) { - if (!node.definition || !node.definition.ident || this.scopeInfos.length === 0) return; - if (this.scopeInfos[this.scopeInfos.length - 1]?.name === node.definition.ident.name) { - this.scopeInfos.pop(); - } + exitStruct(node: arkts.ETSStructDeclaration | arkts.ClassDeclaration): void { + if (!node.definition || !node.definition.ident || this.scopeInfos.length === 0) { + return; } - if (arkts.isClassDeclaration(node)) { - this.classNode = undefined; + if (this.scopeInfos[this.scopeInfos.length - 1]?.name === node.definition.ident.name) { + this.scopeInfos.pop(); } } @@ -222,65 +199,49 @@ export class ComponentTransformer extends AbstractVisitor { navInterface.modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_EXPORT; return arkts.factory.updateETSModule(node, [...this.imports.splice(0), ...node.statements, navInterface], node.ident, node.getNamespaceFlag(), node.program); } - if (this.isExternal && this.entryNames.length === 0 && NamespaceProcessor.getInstance().totalInterfacesCnt === 0) { + if ( + this.isExternal && + this.entryInfos.length === 0 && + NamespaceProcessor.getInstance().totalInterfacesCnt === 0 + ) { return node; } - this.insertComponentImport(); - - const updateStatements: arkts.Statement[] = []; - if (this.shouldAddLinkIntrinsic) { - const expr = arkts.factory.createIdentifier(DecoratorIntrinsicNames.LINK); - updateStatements.push(factory.createIntrinsicAnnotationDeclaration({ expr })); - } - - if (this.entryNames.length > 0) { - if (!this.isEntryPointImported) this.imports.push(entryFactory.createAndInsertEntryPointImport(this.program)); - // normally, we should only have at most one @Entry component in a single file. - // probably need to handle error message here. - if (!this.isPageLifeCycleImported) - this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.PAGE_LIFE_CYCLE); - updateStatements.push(...this.entryNames.map(entryFactory.generateEntryWrapper)); - updateStatements.push( - entryFactory.callRegisterNamedRouter(this.entryRouteName, this.projectConfig, this.program?.absoluteName) - ); - this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, NavigationNames.NAVINTERFACE); - } - - if (this.resourceCollection.size > 0) { - this.resourceCollection.forEach((resourceName: string) => { - this.createImportDeclaration(RESOURCE_IMPORT_SOURCE_NAME, resourceName); - }) - } - + const updateStatements: arkts.Statement[] = this.generateStatementsForEntry(); if (updateStatements.length > 0 || this.imports.length > 0) { - return arkts.factory.updateETSModule(node, [...this.imports.splice(0), ...node.statements, ...updateStatements], node.ident, node.getNamespaceFlag(), node.program); + const newStatements = collect(this.imports.splice(0), node.statements, updateStatements); + return arkts.factory.updateETSModule(node, newStatements, node.ident, node.getNamespaceFlag(), node.program); } return node; } insertComponentImport(): void { - if (!this.isCustomComponentImported && this.componentType.hasComponent) { + if (this.componentType.hasComponent) { this.createImportDeclaration( CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.COMPONENT_CLASS_NAME ); } - if (!this.isCustomComponentV2Imported && this.componentType.hasComponentV2) { + if (this.componentType.hasComponentV2) { this.createImportDeclaration( CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.COMPONENT_V2_CLASS_NAME ); } - if (!this.isBaseCustomDialogImported && this.componentType.hasCustomDialog) { + if (this.componentType.hasCustomDialog) { this.createImportDeclaration( CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.BASE_CUSTOM_DIALOG_NAME ); } - if (!this.isLayoutCallbackImported && this.componentType.hasCustomLayout) { + if (this.componentType.hasCustomLayout) { this.createImportDeclaration(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, CustomComponentNames.LAYOUT_CALLBACKS); } + if (this.resourceCollection.size > 0) { + this.resourceCollection.forEach((resourceName: string) => { + this.createImportDeclaration(RESOURCE_IMPORT_SOURCE_NAME, resourceName); + }) + } } updateEntryPoint(node: arkts.ClassDeclaration): arkts.ClassDeclaration { @@ -305,15 +266,6 @@ export class ComponentTransformer extends AbstractVisitor { ); } - updateDollarVariableAccess(node: arkts.Identifier) { - return arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(node.name.slice(1)), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, false - ); - } - createStaticMethod(definition: arkts.ClassDefinition): arkts.MethodDefinition { const isDecl: boolean = arkts.hasModifierFlag(definition, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); const modifiers = @@ -356,7 +308,26 @@ export class ComponentTransformer extends AbstractVisitor { if (!className || scopeInfo?.name !== className) { return node; } + if (scopeInfo.type === StructType.INVALID_STRUCT) { + LogCollector.getInstance().collectLogInfo({ + node: node, + message: `Annotation '@Component', '@ComponentV2', or '@CustomDialog' is missing for struct '${className}'.`, + level: LogType.ERROR, + }); + return node; + } + if (scopeInfo.type === StructType.CUSTOM_COMPONENT_DECL) { + return node; + } if (arkts.isETSStructDeclaration(node)) { + if (node.definition.super || node.definition.implements.length !== 0) { + LogCollector.getInstance().collectLogInfo({ + node: node.definition?.ident ?? node, + message: `Structs are not allowed to inherit from classes or implement interfaces.`, + level: LogType.ERROR, + }); + return node; + } this.collectComponentMembers(node, className); } const customComponentInterface = this.generateComponentInterface( @@ -365,27 +336,22 @@ export class ComponentTransformer extends AbstractVisitor { Object.values(scopeInfo.annotations ?? {}).map((anno) => anno.clone()) ); NamespaceProcessor.getInstance().addInterfaceToCurrentNamespace(customComponentInterface); - const definition: arkts.ClassDefinition = node.definition!; + const definition: arkts.ClassDefinition = this.rewriteStructDefinition(node, node.definition!) const newDefinitionBody: arkts.AstNode[] = []; if (!!scopeInfo.annotations?.entry) { - this.entryNames.push(className); - const { storage, useSharedStorage, routeName } = getEntryParams(definition); - entryFactory.transformStorageParams(storage, useSharedStorage, definition); - if (routeName && routeName.value && arkts.isStringLiteral(routeName.value)) { - this.entryRouteName = routeName.value.str; - } + this.entryInfos.push({ className, annotation: scopeInfo.annotations.entry, definition }); } const newDefinition: arkts.ClassDefinition = this.createNewDefinition( node, className, definition, - newDefinitionBody + newDefinitionBody, + scopeInfo ); if (arkts.isETSStructDeclaration(node)) { newDefinition.setFromStructModifier() - const _node = arkts.factory.createClassDeclaration(newDefinition); - _node.modifiers = node.modifiers; + const _node = arkts.factory.createClassDeclaration(newDefinition, node.modifierFlags); _node.startPosition = node.startPosition; _node.endPosition = node.endPosition; return _node; @@ -398,7 +364,8 @@ export class ComponentTransformer extends AbstractVisitor { node: arkts.ClassDeclaration | arkts.ETSStructDeclaration, className: string, definition: arkts.ClassDefinition, - newDefinitionBody: arkts.AstNode[] + newDefinitionBody: arkts.AstNode[], + scopeInfo: StructInfo ): arkts.ClassDefinition { const staticMethodBody: arkts.AstNode[] = []; const hasExportFlag = @@ -410,8 +377,7 @@ export class ComponentTransformer extends AbstractVisitor { staticMethodBody.push(buildCompatibleNode); } } - const scopeInfo = this.scopeInfos[this.scopeInfos.length - 1]; - const extendsName: string = getComponentExtendsName(scopeInfo.annotations, this.componentType); + const extendsName: string = getComponentExtendsName(scopeInfo.annotations!, this.componentType); if (!this.hasMemoStableImported) { this.hasMemoStableImported = true; this.createImportDeclaration(MEMO_IMPORT_SOURCE_NAME, MemoNames.MEMO_STABLE); @@ -421,7 +387,7 @@ export class ComponentTransformer extends AbstractVisitor { definition.ident, undefined, undefined, // superTypeParams doen't work - [...definition.implements, ...factory.generateImplementsForStruct(scopeInfo.annotations)], + collect(definition.implements, factory.generateImplementsForStruct(scopeInfo.annotations!)), undefined, arkts.factory.createETSTypeReference( arkts.factory.createETSTypeReferencePart( @@ -434,13 +400,13 @@ export class ComponentTransformer extends AbstractVisitor { ]) ) ), - [ - ...newDefinitionBody, - ...definition.body.map((st: arkts.AstNode) => + collect( + newDefinitionBody, + definition.body.map((st: arkts.AstNode) => factory.PreprocessClassPropertyModifier(st, scopeInfo.isDecl) ), - ...staticMethodBody, - ], + staticMethodBody, + ), definition.modifiers, arkts.classDefinitionFlags(definition) | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_FINAL, [annotation(MemoNames.MEMO_STABLE), ...definition.annotations] @@ -481,42 +447,129 @@ export class ComponentTransformer extends AbstractVisitor { } createInterfaceInnerMember(member: arkts.ClassProperty): arkts.ClassProperty[] { + const infos = findDecoratorInfos(member); + 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 - ); - const infos: DecoratorInfo[] = findDecoratorInfos(member); - const buildParamInfo: DecoratorInfo | undefined = infos.find((it) => - isDecoratorAnnotation(it.annotation, DecoratorNames.BUILDER_PARAM, true) - ); - const optionsHasMember = factory.createOptionsHasMember(originalName); - if (!!buildParamInfo) { - originMember.setAnnotations([buildParamInfo.annotation.clone()]); - return [originMember, optionsHasMember]; - } - const targetInfo = infos.find((it) => DECORATOR_TYPE_MAP.has(it.name)); - if (!!targetInfo) { - const newName: string = backingField(originalName); - const newMember: arkts.ClassProperty = propertyFactory.createOptionalClassProperty( - newName, + const originMember: arkts.ClassProperty = propertyFactory + .createOptionalClassProperty( + originalName, member, undefined, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC - ); - newMember.setAnnotations(member.annotations); - if (isDecoratorAnnotation(targetInfo.annotation, DecoratorNames.LINK, true)) { - this.shouldAddLinkIntrinsic = true; - originMember.setAnnotations([annotation(DecoratorIntrinsicNames.LINK)]); - } + ) + .setAnnotations(annotations); + const optionsHasMember = factory.createOptionsHasMember(originalName); + 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( + newName, + member, + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ) + .setAnnotations(typedAnnotations); return [originMember, newMember, optionsHasMember]; } return [originMember, optionsHasMember]; } - processResourceCall(node: arkts.CallExpression): arkts.CallExpression { + visitStruct(node: arkts.ETSStructDeclaration): arkts.ETSStructDeclaration | arkts.ClassDeclaration { + this.enterStruct(node); + if (this.scopeInfos.length > 0 && isComponentStruct(node, this.scopeInfos[this.scopeInfos.length - 1])) { + const updateNode = this.processComponent(node); + this.exitStruct(updateNode); + return updateNode; + } + return node; + } + + visitETSModule(node: arkts.ETSModule): arkts.ETSModule { + NamespaceProcessor.getInstance().enter(); + const isNamespace = node.isNamespace; + const newStatements = node.statements.map((st) => { + if (arkts.isETSStructDeclaration(st)) { + return this.visitStruct(st); + } + if (arkts.isETSModule(st)) { + return this.visitETSModule(st); + } + if (!isNamespace) { + if ( + arkts.isClassDeclaration(st) && + this.externalSourceName === CUSTOM_COMPONENT_IMPORT_SOURCE_NAME && + st.definition?.ident?.name === EntryWrapperNames.ENTRY_POINT_CLASS_NAME + ) { + return this.updateEntryPoint(st); + } + if ( + arkts.isTSInterfaceDeclaration(st) && + isCustomDialogControllerOptions(st, this.externalSourceName) + ) { + return factory.updateCustomDialogOptionsInterface(st); + } + if (arkts.isClassDeclaration(st)) { + return arkts.factory.updateClassDeclaration(st, this.rewriteStructDefinition(st, st.definition)) + } + } + return st; + }); + let newNode = arkts.factory.updateETSModule(node, newStatements, node.ident, node.getNamespaceFlag(), node.program); + if (isNamespace) { + newNode = NamespaceProcessor.getInstance().updateCurrentNamespace(newNode); + } else { + newNode = NamespaceProcessor.getInstance().updateCurrentNamespace(this.processRootEtsScript(newNode)); + } + NamespaceProcessor.getInstance().exit(); + return newNode; + } + + visitor(node: arkts.AstNode): arkts.AstNode { + if (!arkts.isETSModule(node)) { + return node; + } + return this.visitETSModule(node); + } + + private rewriteStructDefinition(classDecl: arkts.ClassDeclaration, classDefinition: arkts.ClassDefinition): arkts.ClassDefinition { + return new StructDefinitionTransformer(this.resourceCollection, this.projectConfig, this.resourceInfo, classDecl).process(classDefinition) as arkts.ClassDefinition; + } +} + +class StructDefinitionTransformer extends AbstractVisitor { + constructor(private resourceCollection: Set, + private projectConfig: ProjectConfig | undefined, + private readonly resourceInfo: ResourceInfo, + private classNode: arkts.ClassDeclaration | undefined) { + super(); + } + + process(node: arkts.ClassDefinition): arkts.AstNode { + arkts.filterNodes(node, `type=call`, true).forEach((node) => { + if (isResourceNode(node as arkts.CallExpression, true)) { + this.processResourceCall(node as arkts.CallExpression) + } + }); + arkts.filterNodes(node, `annotation=${DecoratorNames.TYPE}`, true).forEach((node) => { + if (arkts.isClassProperty(node)) { + this.processClassPropertyWithTypeAnno(node) + } + }); + return this.visitor(node); + } + + private processClassPropertyWithTypeAnno(property: arkts.ClassProperty) { + property.setAnnotations( + property.annotations.filter((anno) => + anno.baseName?.name !== DecoratorNames.TYPE) + ); + console.warn(`[UI PLUGIN] @Type decorator needs to be added to stateManagement/decorator.d.ets`) + } + + private processResourceCall(node: arkts.CallExpression): arkts.CallExpression { if (node.callee && arkts.isIdentifier(node.callee)) { const originalName = node.callee.name const updatedNode = resourceFactory.transformResource(node, this.projectConfig, this.resourceInfo); @@ -529,65 +582,19 @@ export class ComponentTransformer extends AbstractVisitor { return node; } + private updateDollarVariableAccess(node: arkts.Identifier) { + return arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier(node.name.slice(1)), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, false + ); + } + visitor(node: arkts.AstNode): arkts.AstNode { - this.enter(node); - if (arkts.isETSModule(node)) { - NamespaceProcessor.getInstance().enter(); - } - const newNode = this.visitEachChild(node); - if (arkts.isETSModule(newNode)) { - let res: arkts.ETSModule; - if (newNode.isNamespace) { - res = NamespaceProcessor.getInstance().updateCurrentNamespace(newNode); - } else { - res = NamespaceProcessor.getInstance().updateCurrentNamespace(this.processRootEtsScript(newNode)); - } - NamespaceProcessor.getInstance().exit(); - return res; + if (arkts.isIdentifier(node) && isDollarVariable(node, this.classNode)) { + return this.updateDollarVariableAccess(node) } - if ( - arkts.isETSStructDeclaration(newNode) && - this.scopeInfos.length > 0 && - isComponentStruct(newNode, this.scopeInfos[this.scopeInfos.length - 1]) - ) { - const componentV2WithPropsAnno = newNode.definition.annotations.find(anno => { - return anno.baseName?.name === StructDecoratorNames.COMPONENT_V2 && anno.properties.length > 0; - }) - if (componentV2WithPropsAnno != undefined) { - componentV2WithPropsAnno.setProperties([]) - console.warn(`[UI PLUGIN] @ComponentV2 does not support parameters yet`) - } - const updateNode = this.processComponent(newNode); - this.exit(newNode); - return updateNode; - } - if ( - arkts.isClassDeclaration(newNode) && - this.externalSourceName === CUSTOM_COMPONENT_IMPORT_SOURCE_NAME && - newNode.definition?.ident?.name === EntryWrapperNames.ENTRY_POINT_CLASS_NAME - ) { - return this.updateEntryPoint(newNode); - } - if (arkts.isClassProperty(newNode) && hasDecoratorName(newNode, DecoratorNames.TYPE)) { - newNode.setAnnotations( - newNode.annotations.filter((anno) => - anno.baseName?.name !== DecoratorNames.TYPE) - ); - console.warn(`[UI PLUGIN] @Type decorator needs to be added to stateManagement/decorator.d.ets`) - return newNode; - } - if ( - arkts.isTSInterfaceDeclaration(newNode) && - isCustomDialogControllerOptions(newNode, this.externalSourceName) - ) { - return factory.updateCustomDialogOptionsInterface(newNode); - } - if (arkts.isCallExpression(newNode) && isResourceNode(newNode, true)) { - return this.processResourceCall(newNode); - } - if (arkts.isIdentifier(newNode) && isDollarVariable(newNode, this.classNode)) { - return this.updateDollarVariableAccess(newNode) - } - return newNode; + return this.visitEachChild(node); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/cache/conditionBreakCache.ts b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/cache/conditionBreakCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..693053ba845fb8e44250f622dcf3ddf1d8a9c3a2 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/cache/conditionBreakCache.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'; + +export class ConditionBreakCache { + private _shouldBreak: boolean; + private _shouldReturn: boolean; + private _shouldContinue: boolean; + private static instance: ConditionBreakCache | null = null; + + private constructor() { + this._shouldBreak = false; + this._shouldReturn = false; + this._shouldContinue = false; + } + + static getInstance(): ConditionBreakCache { + if (!this.instance) { + this.instance = new ConditionBreakCache(); + } + return this.instance; + } + + get shouldBreak(): boolean { + return this._shouldBreak; + } + + get shouldReturn(): boolean { + return this._shouldReturn; + } + + get shouldContinue(): boolean { + return this._shouldContinue; + } + + collectBreak(): void { + if (this._shouldBreak) { + return; + } + this._shouldBreak = true; + } + + collectReturn(): void { + if (this._shouldReturn) { + return; + } + this._shouldReturn = true; + } + + collectContinue(): void { + if (this._shouldContinue) { + return; + } + this._shouldContinue = true; + } + + collect(st: arkts.AstNode): boolean { + if (arkts.isBreakStatement(st)) { + this.collectBreak(); + return true; + } + if (arkts.isReturnStatement(st)) { + this.collectReturn(); + return true; + } + if (arkts.isContinueStatement(st)) { + this.collectContinue(); + return true; + } + return false; + } + + reset(): void { + this._shouldBreak = false; + this._shouldReturn = false; + this._shouldContinue = false; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-factory.ts b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..fdd606900a697060ecc7a3354a2ecdd2c25788bc --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-factory.ts @@ -0,0 +1,297 @@ +/* + * 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 { addMemoAnnotation, MemoNames } from '../../collectors/memo-collectors/utils'; +import { ARKUI_BUILDER_SOURCE_NAME, ConditionNames, NodeCacheNames } from '../../common/predefines'; +import { annotation, coerceToAstNode } from '../../common/arkts-utils'; +import { ImportCollector } from '../../common/import-collector'; +import { BuilderLambdaConditionBranchInfo, checkIsWithInIfConditionScope } from '../builder-lambda-translators/utils'; +import { ConditionBreakCache } from './cache/conditionBreakCache'; +import { factory as UIFactory } from '../ui-factory'; +import { ConditionScopeInfoCache } from '../memo-collect-cache'; +import { ConditionScopeCacheVisitor } from './condition-scope-visitor'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export class ConditionScopeFactory { + /** + * update trailing lambda contents in a builder lambda call. + */ + static updateConditionScopeContentBodyInBuilderLambda( + statement: arkts.Statement, + hasBuilder?: boolean + ): arkts.Statement { + if (arkts.isCallExpression(statement)) { + return statement; + } + if (arkts.isIfStatement(statement)) { + const newStatement = this.updateIfElseContentBodyInBuilderLambda(statement, hasBuilder); + return newStatement; + } + if (arkts.isSwitchStatement(statement)) { + return this.updateSwitchCaseContentBodyInBuilderLambda(statement, hasBuilder); + } + if (arkts.isBlockStatement(statement)) { + const newStatements = statement.statements.map((st) => + this.updateConditionScopeContentBodyInBuilderLambda(st, hasBuilder) + ); + statement.setStatements(newStatements); + return statement; + } + if (arkts.isBreakStatement(statement) && statement.parent && arkts.isBlockStatement(statement.parent)) { + ConditionBreakCache.getInstance().collectBreak(); + return arkts.factory.createReturnStatement(); + } + return statement; + } + + /** + * update if-else in a builder lambda call's arguments. + */ + static updateIfElseContentBodyInBuilderLambda(statement: arkts.Statement, shouldWrap?: boolean): arkts.Statement { + if (arkts.isIfStatement(statement)) { + const alternate = !!statement.alternate + ? this.updateIfElseContentBodyInBuilderLambda(statement.alternate, shouldWrap) + : statement.alternate; + const consequence = !!statement.consequent + ? this.updateIfElseContentBodyInBuilderLambda(statement.consequent, shouldWrap) + : statement.consequent; + statement.setConsequent(consequence); + statement.setAlternate(alternate); + return !shouldWrap || checkIsWithInIfConditionScope(statement) + ? statement + : this.wrapConditionToBlock([statement], ConditionNames.CONDITION_SCOPE); + } + if (arkts.isBlockStatement(statement)) { + let { statements, breakIndex } = this.updateConditionBranchInScope(statement.statements, shouldWrap); + if (!!shouldWrap && checkIsWithInIfConditionScope(statement)) { + const beforeBreak = this.wrapConditionToBlock( + breakIndex > 0 ? statements.slice(0, breakIndex) : statements, + ConditionNames.CONDITION_BRANCH + ); + // beforeBreak.parent = statement; + const afterBreak = breakIndex > 0 ? statements.slice(breakIndex) : []; + statements = [beforeBreak, ...afterBreak]; + } + statement.setStatements(statements); + return statement; + } + return statement; + } + + /** + * wrap `ConditionScope` or `ConditionBranch` builder function to the block statements. + */ + static wrapConditionToBlock(statements: readonly arkts.Statement[], condition: ConditionNames): arkts.Statement { + const contentArg = arkts.factory.createArrowFunctionExpression( + UIFactory.createScriptFunction({ + body: arkts.factory.createBlockStatement(statements), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + }) + ); + contentArg.setAnnotations([annotation(MemoNames.MEMO_UI)]); + const newCall = arkts.factory.createCallExpression(arkts.factory.createIdentifier(condition), [ + contentArg, + ], undefined, false, false); + const newStatement = arkts.factory.createExpressionStatement(newCall); + ConditionScopeInfoCache.getInstance().collect({ arg: contentArg, call: newCall }); + ImportCollector.getInstance().collectSource(condition, ARKUI_BUILDER_SOURCE_NAME); + ImportCollector.getInstance().collectImport(condition); + return newStatement; + } + + /** + * update ConditionBranch in an if-else or swith-case body. + * @internal + */ + static updateConditionBranchInScope( + statements: readonly arkts.Statement[], + shouldWrap?: boolean + ): BuilderLambdaConditionBranchInfo { + let breakIndex = statements.length; + const newStatements = statements.map((st, index) => { + if (ConditionBreakCache.getInstance().collect(st)) { + breakIndex = index; + } + return this.updateConditionScopeContentBodyInBuilderLambda(st, shouldWrap); + }); + return { statements: newStatements, breakIndex }; + } + + /** + * update switch-case in a builder lambda call's arguments. + */ + static updateSwitchCaseContentBodyInBuilderLambda( + statement: T, + shouldWrap?: boolean, + stopAtBuilderLambda?: boolean + ): T { + if (arkts.isSwitchStatement(statement)) { + const cases = statement.cases.map((c) => + this.updateSwitchCaseContentBodyInBuilderLambda(c, shouldWrap, stopAtBuilderLambda) + ); + const newStatement = arkts.factory.updateSwitchStatement(statement, statement.discriminant, cases); + return (!shouldWrap + ? newStatement + : this.wrapConditionToBlock([newStatement], ConditionNames.CONDITION_SCOPE)) as arkts.AstNode as T; + } + if (arkts.isSwitchCaseStatement(statement)) { + let { statements, breakIndex } = this.updateConditionBranchInScope(statement.consequent, shouldWrap); + if (shouldWrap && breakIndex > 0) { + const hasBreak = breakIndex !== statements.length; + const beforeBreak = this.wrapConditionToBlock( + statements.slice(0, breakIndex), + ConditionNames.CONDITION_BRANCH + ); + const afterBreak = statements.slice(hasBreak ? breakIndex + 1 : breakIndex); + const breakStatement = this.createBreakBetweenConditionStatements(); + statements = [beforeBreak, ...breakStatement, ...afterBreak]; + } + ConditionBreakCache.getInstance().reset(); + return arkts.factory.updateSwitchCaseStatement(statement, statement.test, statements) as T; + } + return statement; + } + + /** + * create internal `break` or `return` from `ConditionBreakCache`. + * + * @internal + */ + static createBreakBetweenConditionStatements(): arkts.Statement[] { + const cache = ConditionBreakCache.getInstance(); + if (cache.shouldBreak) { + return [arkts.factory.createBreakStatement()]; + } + if (cache.shouldReturn) { + return [arkts.factory.createReturnStatement()]; + } + return []; + } + + /** + * rewrite `@Builder` function body with `ConditionScopeCacheVisitor`. + * + * @internal + */ + static rewriteBuilderScriptFunction(node: T): arkts.ScriptFunction { + const _node = coerceToAstNode(node); + let params = (_node.params as arkts.ETSParameterExpression[]).map((p) => + addMemoAnnotation(p, MemoNames.MEMO_SKIP_UI) + ); + let funcBody: arkts.AstNode | undefined = _node.body; + if (!funcBody || !arkts.isBlockStatement(funcBody)) { + return _node; + } + const conditionScopeVisitor = ConditionScopeCacheVisitor.getInstance(); + const newStatements = funcBody.statements.map((st) => { + const newNode = conditionScopeVisitor.visitor(st); + conditionScopeVisitor.reset(); + return newNode as arkts.Statement; + }); + funcBody.setStatements(newStatements); + _node.setParams(params); + return _node; + } + + /** + * rewrite `@Builder` method. + */ + static rewriteBuilderMethod(node: T): arkts.MethodDefinition { + const _node = coerceToAstNode(node); + const newFunc = this.rewriteBuilderScriptFunction(_node.function); + const newNode = arkts.factory.updateMethodDefinition( + _node, + _node.kind, + _node.key, + arkts.factory.createFunctionExpression(undefined, newFunc), + _node.modifiers, + false + ); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + NodeCacheFactory.getInstance().refresh(_node.function, newNode.function) + NodeCacheFactory.getInstance().refreshUpdate(_node.function, newNode.function) + return newNode; + } + + /** + * rewrite `@Builder` class property with arrow function value. + */ + static rewriteBuilderClassProperty(node: T): arkts.ClassProperty { + const _node = coerceToAstNode(node); + const value = _node.value; + if (!value || !arkts.isArrowFunctionExpression(value)) { + return _node; + } + const newValue = this.rewriteBuilderArrowFunction(value); + const newNode = arkts.factory.updateClassProperty( + _node, + _node.key, + newValue, + _node.typeAnnotation, + _node.modifiers, + false, + _node.annotations + ); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + return newNode; + } + + /** + * rewrite `@Builder` property with arrow function value. + */ + static rewriteBuilderProperty(node: T): arkts.Property { + const _node = coerceToAstNode(node); + const value = _node.value; + if (!value || !arkts.isArrowFunctionExpression(value)) { + return _node; + } + const newValue = this.rewriteBuilderArrowFunction(value); + _node.setValue(newValue); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + return _node; + } + + /** + * rewrite `@Builder` arrow function. + */ + static rewriteBuilderArrowFunction( + node: T + ): arkts.ArrowFunctionExpression { + const _node = coerceToAstNode(node); + const newFunc = this.rewriteBuilderScriptFunction(_node.function); + const newNode = arkts.factory.updateArrowFunctionExpression(_node, newFunc, _node.annotations); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + return newNode; + } + + /** + * rewrite `@Builder` parameter with arrow function value. + */ + static rewriteBuilderParameter( + node: T + ): arkts.ETSParameterExpression { + const _node = coerceToAstNode(node); + const initializer = _node.initializer; + if (!initializer || !arkts.isArrowFunctionExpression(initializer)) { + return _node; + } + const newInitializer = this.rewriteBuilderArrowFunction(initializer); + _node.setInitializer(newInitializer); + ConditionScopeInfoCache.getInstance().updateAll().reset(); + return _node; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-visitor.ts b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-visitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3c28452ec9e10e3512ee10fd3278a8b149b305c --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/condition-scope-translators/condition-scope-visitor.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 { AbstractVisitor } from '../../common/abstract-visitor'; +import { NodeCacheNames } from '../../common/predefines'; +import { ConditionScopeFactory } from './condition-scope-factory'; +import { NodeCacheFactory } from '../../common/node-cache'; + +/** + * `ConditionScopeCacheVisitor` is used to visit `@Builder` function body to wrap `ConditionScope`/`ConditionBranch` + * to if-else or switch-case statements. + * + * @internal + */ +export class ConditionScopeCacheVisitor extends AbstractVisitor { + private static instance: ConditionScopeCacheVisitor; + private _enforceUpdateCondition: boolean = false; + private _shouldUpdateCondition: boolean = true; + + private get shouldUpdateCondition(): boolean { + if (this._enforceUpdateCondition) { + return true; + } + return this._shouldUpdateCondition; + } + + private set shouldUpdateCondition(newValue: boolean) { + if (this._enforceUpdateCondition) { + this._shouldUpdateCondition = true; + return; + } + this._shouldUpdateCondition = newValue; + } + + static getInstance(): ConditionScopeCacheVisitor { + if (!this.instance) { + this.instance = new ConditionScopeCacheVisitor(); + } + return this.instance; + } + + private enter(node: arkts.AstNode): void { + if ( + arkts.isVariableDeclarator(node) && + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) + ) { + this._enforceUpdateCondition = true; + } + } + + reset(): void { + this._enforceUpdateCondition = false; + this._shouldUpdateCondition = true; + } + + visitor(node: arkts.AstNode): arkts.AstNode { + this.enter(node); + if (arkts.isIfStatement(node) && this.shouldUpdateCondition) { + const newStatement = ConditionScopeFactory.updateIfElseContentBodyInBuilderLambda(node, true); + return newStatement; + } + if (arkts.isSwitchStatement(node) && this.shouldUpdateCondition) { + return ConditionScopeFactory.updateSwitchCaseContentBodyInBuilderLambda(node, true); + } + if (arkts.isBlockStatement(node) && this.shouldUpdateCondition) { + const newStatements = node.statements.map((st) => + ConditionScopeFactory.updateConditionScopeContentBodyInBuilderLambda(st, true) + ); + node.setStatements(newStatements); + return node; + } + if ( + arkts.isArrowFunctionExpression(node) && + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node) && + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node.function) + ) { + this.shouldUpdateCondition = false; + this._enforceUpdateCondition = false; + } + return this.visitEachChild(node); + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/entry-translators/cache-factory.ts b/ui2abc/arkui-plugins/ui-plugins/entry-translators/cache-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..6eea9e3e3ad1795a788ea0ec903c6654c18104dc --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/entry-translators/cache-factory.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 { NormalClassMethodInfo } from '../../collectors/ui-collectors/records'; +import { EntryWrapperNames, NodeCacheNames } from '../../common/predefines'; +import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; +import { NodeCacheFactory } from '../../common/node-cache'; + +export class CacheFactory { + /** + * add `@memo` to `__EntryWrapper` class's `entry` method. + * + * @param node method definition node + * @param metadata normal class method information + */ + static addMemoToEntryWrapperClassMethodFromInfo( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo + ): void { + if (metadata.name === EntryWrapperNames.ENTRY_FUNC) { + addMemoAnnotation(node.function); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(node); + } + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/entry-translators/factory.ts b/ui2abc/arkui-plugins/ui-plugins/entry-translators/factory.ts index 62c8ab63f73efab771bfce164b3ae830cbeea379..e0110f3195ac5a55ed56b83f033e08026f0f4a9f 100644 --- a/ui2abc/arkui-plugins/ui-plugins/entry-translators/factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/entry-translators/factory.ts @@ -16,11 +16,17 @@ import * as arkts from '@koalaui/libarkts'; import * as path from 'path'; import { annotation } from '../../common/arkts-utils'; -import { CUSTOM_COMPONENT_IMPORT_SOURCE_NAME, EntryWrapperNames, NavigationNames } from '../../common/predefines'; +import { + CUSTOM_COMPONENT_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'; -import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; +import { addMemoAnnotation, MemoNames } from '../../collectors/memo-collectors/utils'; +import { NodeCacheFactory } from '../../common/node-cache'; export class factory { /** @@ -224,8 +230,8 @@ export class factory { !!member.function!.id && member.function!.id.name === EntryWrapperNames.ENTRY_FUNC ) { - addMemoAnnotation(member.function!); - arkts.MemoNodeCache.getInstance().collect(member); + addMemoAnnotation(member.function); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(member); } }); } @@ -246,7 +252,7 @@ export class factory { arkts.isIdentifier(member.key) && member.key.name === EntryWrapperNames.ENTRY_FUNC ) { - member.setAnnotations([annotation('memo')]); + member.setAnnotations([annotation(MemoNames.MEMO_UI)]); } }); } @@ -272,7 +278,7 @@ export class factory { * create and insert `import { EntryPoint as EntryPoint } from "arkui.component.customComponent";` * to the top of script's statements. */ - static createAndInsertEntryPointImport(program?: arkts.Program) { + static createEntryPointImport(program?: arkts.Program) { const source: arkts.StringLiteral = arkts.factory.createStringLiteral(CUSTOM_COMPONENT_IMPORT_SOURCE_NAME); const imported: arkts.Identifier = arkts.factory.createIdentifier(EntryWrapperNames.ENTRY_POINT_CLASS_NAME); // Insert this import at the top of the script's statements. @@ -311,12 +317,10 @@ export class factory { if (useSharedStorage && useSharedStorage.value && arkts.isBooleanLiteral(useSharedStorage.value)) { sharedArg = useSharedStorage.value; } - let storageArg: arkts.Expression = arkts.factory.createUndefinedLiteral(); if (storage && storage.value && arkts.isStringLiteral(storage.value)) { storageArg = arkts.factory.createIdentifier(storage.value.str) } - const superCall = arkts.factory.createExpressionStatement( arkts.factory.createCallExpression(arkts.factory.createSuperExpression(), [ sharedArg, diff --git a/ui2abc/arkui-plugins/ui-plugins/entry-translators/utils.ts b/ui2abc/arkui-plugins/ui-plugins/entry-translators/utils.ts index 5783f94ca15adc497d89193fc661530bfbed2a6e..e8bf3aad55d1237b6d539b08e21e3409bcc44047 100644 --- a/ui2abc/arkui-plugins/ui-plugins/entry-translators/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/entry-translators/utils.ts @@ -62,18 +62,28 @@ export function isEntryWrapperClass(node: arkts.AstNode): node is arkts.ClassDec * get annotation's properties in `@Entry()`: storage, useSharedStorage, routeName. * * @param node class definition node + * @deprecated */ export function getEntryParams(node: arkts.ClassDefinition): Record { const annotation = node.annotations.find((anno) => isAnnotation(anno, StructDecoratorNames.ENTRY)); + return getEntryParamsFromAnnotation(annotation); +} + +/** + * get annotation's properties in `@Entry()`: storage, useSharedStorage, routeName. + * + * @param node `@Entry` annotation, expected from a class defintion. + */ +export function getEntryParamsFromAnnotation(node: arkts.AnnotationUsage | undefined): Record { const result = { storage: undefined, useSharedStorage: undefined, routeName: undefined, } as Record; - if (!annotation || !annotation.properties) { + if (!node || !node.properties) { return result; } - for (const prop of annotation.properties) { + for (const prop of node.properties) { if (arkts.isClassProperty(prop) && prop.key && arkts.isIdentifier(prop.key)) { const name = prop.key.name as EntryParamNames; if (name in result) { @@ -82,14 +92,14 @@ export function getEntryParams(node: arkts.ClassDefinition): Record compatibleComponent */ -export function generateBuilderCompatible(node: arkts.CallExpression, moduleName: string): arkts.CallExpression { +export function generateBuilderCompatible(node: arkts.CallExpression, callName: string): arkts.CallExpression { let functionName = getFunctionName(node); let param: builderParam = getInitArgs(node); - const initializer = createBuilderInitializer(moduleName, functionName, param); + const initializer = createBuilderInitializer(callName, functionName, param); const updater: arkts.ArrowFunctionExpression = createBuilderUpdate(node); const result = arkts.factory.updateCallExpression( node, arkts.factory.createIdentifier(InteroperAbilityNames.ARKUICOMPATIBLE), - [ - initializer, - updater, - ], + [initializer, updater], undefined, node.isOptional, node.hasTrailingComma, node.trailingBlock ); - NodeCache.getInstance().collect(result); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(result); return result; } @@ -555,4 +560,4 @@ function getFunctionName(node: arkts.CallExpression): string { default: throw Error('Error arguments in Legacy Builder Function'); } -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/ui-plugins/interop/initstatevar.ts b/ui2abc/arkui-plugins/ui-plugins/interop/initstatevar.ts index 239daf8895888998262c97adf0687754437e08f9..b7ade8eca4f7ae304d81c5cf50f52e3527b628f4 100644 --- a/ui2abc/arkui-plugins/ui-plugins/interop/initstatevar.ts +++ b/ui2abc/arkui-plugins/ui-plugins/interop/initstatevar.ts @@ -13,8 +13,6 @@ * limitations under the License. */ - - import * as arkts from '@koalaui/libarkts'; import { BuilderMethodNames, InteroperAbilityNames } from './predefines'; import { annotation, backingField, isAnnotation } from '../../common/arkts-utils'; @@ -22,7 +20,6 @@ import { stateProxy, getWrapValue, setPropertyESValue, createEmptyESValue } from import { hasDecoratorInterop } from './utils'; import { DecoratorNames } from '../../common/predefines'; - export function initialArgs( args: arkts.ObjectExpression, varMap: Map, @@ -51,8 +48,11 @@ export function initialArgs( const annotations = keyProperty.annotations; if (annotations.length === 0) { const valueProperty = arkts.getDecl(value); - if (valueProperty instanceof arkts.ClassProperty && (hasDecoratorInterop(valueProperty, DecoratorNames.PROVIDE) || - hasDecoratorInterop(valueProperty, DecoratorNames.CONSUME))) { + if ( + valueProperty instanceof arkts.ClassProperty && + (hasDecoratorInterop(valueProperty, DecoratorNames.PROVIDE) || + hasDecoratorInterop(valueProperty, DecoratorNames.CONSUME)) + ) { const errorMessage = 'Cannot assign @Provide or @Consume decorated data to regular property.'; logDiagnostic(errorMessage, node); } @@ -64,11 +64,17 @@ export function initialArgs( } else if (hasDecoratorInterop(keyProperty, DecoratorNames.CONSUME)) { const errorMessage = 'The @Consume property cannot be assigned.'; logDiagnostic(errorMessage, node); - } else if (hasDecoratorInterop(keyProperty, DecoratorNames.PROP) || hasDecoratorInterop(keyProperty, DecoratorNames.OBJECT_LINK)) { + } else if ( + hasDecoratorInterop(keyProperty, DecoratorNames.PROP) || + hasDecoratorInterop(keyProperty, DecoratorNames.OBJECT_LINK) + ) { updateProp.push(property); const initParam = processNormal(keyName, value); result.push(...initParam); - } else if (hasDecoratorInterop(keyProperty, DecoratorNames.STATE) || hasDecoratorInterop(keyProperty, DecoratorNames.PROVIDE)) { + } else if ( + hasDecoratorInterop(keyProperty, DecoratorNames.STATE) || + hasDecoratorInterop(keyProperty, DecoratorNames.PROVIDE) + ) { const initParam = processNormal(keyName, value); result.push(...initParam); } else if (hasDecoratorInterop(keyProperty, DecoratorNames.CONSUME)) { @@ -144,35 +150,34 @@ export function logDiagnostic(errorMessage: string, node: arkts.AstNode): void { export function createVariableLet(varName: string, expression: arkts.Expression): arkts.VariableDeclaration { return arkts.factory.createVariableDeclaration( arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, - [arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, - arkts.factory.createIdentifier(varName), - expression - )] + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, + arkts.factory.createIdentifier(varName), + expression + ), + ] ); } function createBackingFieldExpression(varName: string): arkts.TSNonNullExpression { return arkts.factory.createTSNonNullExpression( arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(backingField(varName)), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier(backingField(varName)), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false ) ); } - function getStateProxy(proxyName: string, stateVar: () => arkts.Expression): arkts.Statement { return createVariableLet( proxyName, arkts.factory.createCallExpression( arkts.factory.createIdentifier(InteroperAbilityNames.GETCOMPATIBLESTATE), - [ - stateVar() - ], + [stateVar()], undefined, false, false @@ -182,17 +187,17 @@ function getStateProxy(proxyName: string, stateVar: () => arkts.Expression): ark /** * Processes a nested object literal and generates code to instantiate and populate it using ESValue methods. - * + * * Converts a nested object structure into a sequence of statements that: * 1. Instantiate empty objects via `ESValue.instantiateEmptyObject()` * 2. Sets properties on these objects using `setProperty()` * 3. Nests objects by assigning child objects as properties of parent objects - * + * * @param target - A nested object literal (e.g., { b: { c: { d: '1' }, cc: { d: '1' } } }) * @returns Generated code statements that reconstruct the input object using ESValue APIs * @example * Input: { b: { c: { d: '1' }, cc: { d: '1' } } } - * Output: + * Output: * let param0 = ESValue.instantiateEmptyObject(); * let param00 = ESValue.instantiateEmptyObject(); * param00.setProperty("d", ESValue.wrap("1")); @@ -202,7 +207,12 @@ function getStateProxy(proxyName: string, stateVar: () => arkts.Expression): ark * param0.setProperty("cc", param01); * param.setProperty("b", param0); */ -function processObjectLiteral(target: arkts.ObjectExpression, curParam: string, result: arkts.Statement[], keyName: string): void { +function processObjectLiteral( + target: arkts.ObjectExpression, + curParam: string, + result: arkts.Statement[], + keyName: string +): void { if (curParam !== InteroperAbilityNames.PARAM) { const createParam = createEmptyESValue(curParam); result.push(createParam); @@ -214,26 +224,17 @@ function processObjectLiteral(target: arkts.ObjectExpression, curParam: string, const value = property.value!; if (arkts.isObjectExpression(value)) { processObjectLiteral(value, paramName, result, keyName); - const setProperty = setPropertyESValue( - curParam, - key.name, - arkts.factory.createIdentifier(paramName) - ); + const setProperty = setPropertyESValue(curParam, key.name, arkts.factory.createIdentifier(paramName)); result.push(setProperty); } else { - const setProperty = setPropertyESValue( - curParam, - key.name, - getWrapValue(value) - ); + const setProperty = setPropertyESValue(curParam, key.name, getWrapValue(value)); result.push(setProperty); } }); } - /** - * + * * @param keyName - The name of the state variable (e.g., state) * @returns generate code to process @Link data interoperability * @example @@ -242,7 +243,12 @@ function processObjectLiteral(target: arkts.ObjectExpression, curParam: string, * let __Proxy_state = getCompatibleState(this.state); * param.setProperty("link", __Proxy_state); */ -export function processLink(keyName: string, value: arkts.Expression, type: arkts.TypeNode, proxySet: Set): arkts.Statement[] { +export function processLink( + keyName: string, + value: arkts.Expression, + type: arkts.TypeNode, + proxySet: Set +): arkts.Statement[] { const valueDecl = arkts.getDecl(value); const result: arkts.Statement[] = []; if (valueDecl instanceof arkts.ClassProperty) { @@ -254,11 +260,7 @@ export function processLink(keyName: string, value: arkts.Expression, type: arkt const getProxy = getStateProxy(proxyName, stateVar); result.push(getProxy); } - const setParam = setPropertyESValue( - 'param', - keyName, - arkts.factory.createIdentifier(proxyName) - ); + const setParam = setPropertyESValue('param', keyName, arkts.factory.createIdentifier(proxyName)); result.push(setParam); } else { throw Error('unsupported data for Link'); @@ -267,7 +269,7 @@ export function processLink(keyName: string, value: arkts.Expression, type: arkt } /** - * + * * @param keyName - The name of the state variable (e.g., state) * @returns generate code to process regular data interoperability */ @@ -276,20 +278,16 @@ export function processNormal(keyName: string, value: arkts.Expression): arkts.S if (arkts.isObjectExpression(value)) { processObjectLiteral(value, InteroperAbilityNames.PARAM, result, keyName); } else { - const setProperty = setPropertyESValue( - InteroperAbilityNames.PARAM, - keyName, - getWrapValue(value) - ); + const setProperty = setPropertyESValue(InteroperAbilityNames.PARAM, keyName, getWrapValue(value)); result.push(setProperty); } return result; } /** - * - * @param keyName - * @param value + * + * @param keyName + * @param value * @returns generate code to process @BuilderParam interoperability * @example * Input: {builderParam: this.builder} @@ -299,20 +297,15 @@ export function processBuilderParam(keyName: string, value: arkts.Expression): a const result: arkts.Statement[] = []; const needUpdate: boolean = checkUpdatable(value); const newValue = arkts.factory.createCallExpression( - needUpdate ? arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER) : - arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER), - [ - value - ], + needUpdate + ? arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER) + : arkts.factory.createIdentifier(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER), + [value], undefined, false, false ); - const setProperty = setPropertyESValue( - InteroperAbilityNames.PARAM, - keyName, - newValue - ); + const setProperty = setPropertyESValue(InteroperAbilityNames.PARAM, keyName, newValue); result.push(setProperty); return result; } @@ -320,7 +313,11 @@ export function processBuilderParam(keyName: string, value: arkts.Expression): a function getIdentifier(value: arkts.AstNode): arkts.Identifier | undefined { if (arkts.isIdentifier(value)) { return value; - } else if (arkts.isMemberExpression(value) && arkts.isThisExpression(value.object) && arkts.isIdentifier(value.property)) { + } else if ( + arkts.isMemberExpression(value) && + arkts.isThisExpression(value.object) && + arkts.isIdentifier(value.property) + ) { return value.property; } else { return undefined; @@ -370,4 +367,4 @@ function isNonBuiltinType(type: arkts.AstNode): boolean { return true; } return false; -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/ui-plugins/interop/interop.ts b/ui2abc/arkui-plugins/ui-plugins/interop/interop.ts index dfbd7a8839bf6ac7af7ac833b53d99d459e95df3..8cb39818914b30545f1f0be8d31be9a7cd64e3c5 100644 --- a/ui2abc/arkui-plugins/ui-plugins/interop/interop.ts +++ b/ui2abc/arkui-plugins/ui-plugins/interop/interop.ts @@ -13,26 +13,24 @@ * limitations under the License. */ - - import * as arkts from '@koalaui/libarkts'; import { BuilderMethodNames, ESValueMethodNames, InteroperAbilityNames } from './predefines'; import { getCustomComponentOptionsName } from '../utils'; import { InteropContext } from '../component-transformer'; import { createVariableLet, initialArgs, getPropertyType } from './initstatevar'; import { - getPropertyESValue, - getWrapValue, - setPropertyESValue, - createEmptyESValue, - createGlobal, - createELMTID, - createInitReturn + getPropertyESValue, + getWrapValue, + setPropertyESValue, + createEmptyESValue, + createGlobal, + createELMTID, + createInitReturn, } from './utils'; -import { DecoratorNames, LANGUAGE_VERSION } from '../../common/predefines'; +import { DecoratorNames, LANGUAGE_VERSION, NodeCacheNames } from '../../common/predefines'; import { hasDecoratorInterop } from './utils'; import { FileManager } from '../../common/file-manager'; -import { NodeCache } from '../../common/node-cache'; +import { NodeCacheFactory } from '../../common/node-cache'; function paramsLambdaDeclaration(name: string, args?: arkts.ObjectExpression): arkts.Statement[] { const result: arkts.Statement[] = []; @@ -45,9 +43,17 @@ function paramsLambdaDeclaration(name: string, args?: arkts.ObjectExpression): a arkts.factory.createIdentifier(InteroperAbilityNames.PARAMSLAMBDA), arkts.factory.createArrowFunctionExpression( arkts.factory.createScriptFunction( - arkts.factory.createBlockStatement([arkts.factory.createReturnStatement( - args ? args : arkts.factory.createObjectExpression([]), - )]), + arkts.factory.createBlockStatement([ + arkts.factory.createReturnStatement( + args + ? args + : arkts.ObjectExpression.createObjectExpression( + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + [], + false + ) + ), + ]), undefined, [], arkts.factory.createETSTypeReference( @@ -63,7 +69,6 @@ function paramsLambdaDeclaration(name: string, args?: arkts.ObjectExpression): a ) ) ), - ] ) ); @@ -75,11 +80,7 @@ function createExtraInfo(properties: string[], value: string[]): arkts.Statement body.push(createEmptyESValue(InteroperAbilityNames.EXTRAINFO)); properties.forEach((prop, index) => { const val = value[index]; - body.push(setPropertyESValue( - InteroperAbilityNames.EXTRAINFO, - prop, - arkts.factory.createStringLiteral(val)) - ); + body.push(setPropertyESValue(InteroperAbilityNames.EXTRAINFO, prop, arkts.factory.createStringLiteral(val))); }); return body; } @@ -100,9 +101,7 @@ function generateTSASExpression(expression: arkts.Expression): arkts.Expression false ), arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier('Object') - ) + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Object')) ), false ); @@ -112,37 +111,32 @@ function newComponent(className: string): arkts.Statement { return createVariableLet( InteroperAbilityNames.COMPONENT, getWrapValue( - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createIdentifier(className), - [ - arkts.factory.createUndefinedLiteral(), - generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.PARAM)), - arkts.factory.createUndefinedLiteral(), - generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID)), - arkts.factory.createTSAsExpression( - arkts.factory.createArrowFunctionExpression( - arkts.factory.createScriptFunction( - arkts.factory.createBlockStatement([]), - undefined, - [], - undefined, - false, - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - undefined, - undefined - ) - ), - arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier('Object') - ) - ), - false + arkts.factory.createETSNewClassInstanceExpression(arkts.factory.createIdentifier(className), [ + arkts.factory.createUndefinedLiteral(), + generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.PARAM)), + arkts.factory.createUndefinedLiteral(), + generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID)), + arkts.factory.createTSAsExpression( + arkts.factory.createArrowFunctionExpression( + arkts.factory.createScriptFunction( + arkts.factory.createBlockStatement([]), + undefined, + [], + undefined, + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + undefined, + undefined + ) ), - generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.EXTRAINFO)) - ] - ) + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Object')) + ), + false + ), + generateTSASExpression(arkts.factory.createIdentifier(InteroperAbilityNames.EXTRAINFO)), + ]) ) ); } @@ -163,9 +157,7 @@ function createComponent(className: string, isV2: boolean): arkts.Statement[] { false, false ), - [ - arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT) - ], + [arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT)], undefined, false, false @@ -174,7 +166,6 @@ function createComponent(className: string, isV2: boolean): arkts.Statement[] { return [component, View, create]; } - function createWrapperBlock( context: InteropContext, varMap: Map, @@ -262,25 +253,21 @@ function updateStateVars(updateProp: arkts.Property[]): arkts.Statement[] { ]; } - /** - * - * @param updateProp + * + * @param updateProp * @returns (instance: ESValue) => { instance.invokeMethod('updateStateVars', updateParam) } */ function createUpdater(updateProp: arkts.Property[]): arkts.ArrowFunctionExpression { - const updateState = (updateProp.length !== 0) ? updateStateVars(updateProp) : []; + const updateState = updateProp.length !== 0 ? updateStateVars(updateProp) : []; return arkts.factory.createArrowFunctionExpression( arkts.factory.createScriptFunction( - arkts.factory.createBlockStatement( - [ - ...updateState - ] - ), + arkts.factory.createBlockStatement([...updateState]), undefined, [ arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.INSTANCE, + arkts.factory.createIdentifier( + InteroperAbilityNames.INSTANCE, arkts.factory.createETSTypeReference( arkts.factory.createETSTypeReferencePart( arkts.factory.createIdentifier(ESValueMethodNames.ESVALUE) @@ -308,24 +295,21 @@ function updateArguments(context: InteropContext, name: string): arkts.ObjectExp arkts.factory.createTSAsExpression( context.content, arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier('Function') - ) + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Function')) ), false ), false, false ); - return context.arguments ? arkts.factory.updateObjectExpression( - context.arguments, - [ - ...(context.arguments?.properties as arkts.Property[]), - property - ] - ) : arkts.factory.createObjectExpression( - [property] - ); + return context.arguments + ? arkts.factory.updateObjectExpression( + context.arguments, + [...(context.arguments?.properties as arkts.Property[]), property] + ) + : arkts.factory.createObjectExpression( + [property] + ); } function generateVarMap(context: InteropContext, decl: arkts.ClassDefinition): Map { @@ -333,7 +317,7 @@ function generateVarMap(context: InteropContext, decl: arkts.ClassDefinition): M const result = new Map(); const definition = decl; const body = definition.body; - body.forEach(node => { + body.forEach((node) => { if (node instanceof arkts.ClassProperty && node.key instanceof arkts.Identifier) { const key = node.key.name; result.set(key, node); @@ -346,7 +330,7 @@ function generateVarMap(context: InteropContext, decl: arkts.ClassDefinition): M return result; } -export function processArgumens(arg: arkts.Expression): arkts.ObjectExpression { +export function processArguments(arg: arkts.Expression): arkts.ObjectExpression { if (!arkts.isObjectExpression(arg)) { throw new Error('Cannot find arguments for InteropComponent'); } @@ -357,10 +341,7 @@ export function processArgumens(arg: arkts.Expression): arkts.ObjectExpression { return arkts.factory.updateProperty( property, property.kind, - arkts.factory.updateIdentifier( - key, - key.name.slice('__backing_'.length) - ), + arkts.factory.updateIdentifier(key, key.name.slice('__backing_'.length)), property.value, property.isMethod, property.isComputed @@ -374,10 +355,21 @@ export function processArgumens(arg: arkts.Expression): arkts.ObjectExpression { ); } +function getProperParams(args: readonly arkts.Expression[]): [arkts.ObjectExpression | undefined, arkts.AstNode | undefined] { + if (args.length < 2) { + return [undefined, undefined]; + } else if (args.length === 2) { + if (args[1] instanceof arkts.ArrowFunctionExpression) { + return [undefined, args[1]]; + } + return [processArguments(args[1]), undefined]; + } + return [processArguments(args[1]), args[2]]; +} /** - * - * @param node + * + * @param node * @returns After Checked, transform instantiate_Interop -> ArkUICompatible */ export function generateArkUICompatible(node: arkts.CallExpression, globalBuilder: boolean): arkts.CallExpression { @@ -389,10 +381,10 @@ export function generateArkUICompatible(node: arkts.CallExpression, globalBuilde } const filePath = arkts.getProgramFromAstNode(decl).moduleName; const args = node.arguments; - const options = args.length < 2 || arkts.isUndefinedLiteral(args[1]) ? undefined : processArgumens(args[1]); - const content = args.length < 3 || arkts.isUndefinedLiteral(args[2]) ? undefined : args[2]; + const [options, content] = getProperParams(args); + if (!!content) { - NodeCache.getInstance().collect(content); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(content); } const context: InteropContext = { className: className, @@ -421,7 +413,7 @@ export function generateArkUICompatible(node: arkts.CallExpression, globalBuilde node.hasTrailingComma, node.trailingBlock ); - NodeCache.getInstance().collect(result); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(result); return result; } @@ -471,4 +463,4 @@ function checkObservedForm1_1(typeNode: arkts.AstNode, annotationObserved: strin return true; } return false; -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/ui-plugins/interop/legacy-transformer.ts b/ui2abc/arkui-plugins/ui-plugins/interop/legacy-transformer.ts index 96021ef57dc1fbe9d284eda93fc033631addd550..70c720cf63ce5bac0138cea737da91bbf2c75f74 100644 --- a/ui2abc/arkui-plugins/ui-plugins/interop/legacy-transformer.ts +++ b/ui2abc/arkui-plugins/ui-plugins/interop/legacy-transformer.ts @@ -13,17 +13,15 @@ * limitations under the License. */ - - import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor, VisitorOptions } from '../../common/abstract-visitor'; import { InteroperAbilityNames } from './predefines'; import { getCustomComponentOptionsName } from '../utils'; import { factory } from '../ui-factory'; -import { ImportCollector } from 'common/import-collector'; +import { ImportCollector } from '../../common/import-collector'; interface LegacyTransformerOptions extends VisitorOptions { - structList?: string[] + structList?: string[]; } type ScopeInfo = { @@ -56,9 +54,7 @@ export class LegacyTransformer extends AbstractVisitor { arkts.factory.createIdentifier( name, arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier(type) - ) + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier(type)) ) ), isOptional, @@ -68,24 +64,27 @@ export class LegacyTransformer extends AbstractVisitor { generateMember(map: Map): arkts.ClassProperty[] { const properties: arkts.ClassProperty[] = []; - + map.forEach((value, key) => { - const property = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(key), - undefined, - value, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL, - false - ); - - properties.push(property); + const property = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(key), + undefined, + value, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL, + false + ); + + properties.push(property); }); - + return properties; - } + } - generateComponentInterface(name: string, modifiers: number, map: Map): arkts.TSInterfaceDeclaration { + generateComponentInterface( + name: string, + modifiers: number, + map: Map + ): arkts.TSInterfaceDeclaration { const interfaceNode = arkts.factory.createInterfaceDeclaration( [], arkts.factory.createIdentifier(getCustomComponentOptionsName(name)), @@ -124,18 +123,9 @@ export class LegacyTransformer extends AbstractVisitor { undefined ); const paramContent: arkts.ETSParameterExpression = arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier( - InteroperAbilityNames.CONTENT, - factory.createLambdaFunctionType() - ), + arkts.factory.createIdentifier(InteroperAbilityNames.CONTENT, factory.createLambdaFunctionType()), true, - undefined, - [ - arkts.factory.createAnnotationUsage( - arkts.factory.createIdentifier('Builder'), - [] - ) - ] + undefined ); return [paramFactory, paramInitializers, paramReuseId, paramContent]; } @@ -148,7 +138,7 @@ export class LegacyTransformer extends AbstractVisitor { arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC; const body = isDecl ? undefined : arkts.factory.createBlockStatement([arkts.factory.createReturnStatement()]); - const params = this.createParamsForInstatiate(name); + const params = this.createParamsForInstatiate(name); const returnTypeAnnotation = factory.createTypeReferenceFromString('Object'); const flags = arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD; const kind = arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD; @@ -208,59 +198,52 @@ export class LegacyTransformer extends AbstractVisitor { processConstructor(node: arkts.MethodDefinition): arkts.MethodDefinition { const valueType = arkts.factory.createETSUnionType([ arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier('Object') - ) + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Object')) ), - arkts.factory.createETSUndefinedType() + arkts.factory.createETSUndefinedType(), ]); const script = factory.createScriptFunction({ key: node.id?.clone(), body: arkts.factory.createBlockStatement([]), params: [ - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.PARENT, valueType), - true, - undefined, - ), - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.PARAM, valueType), - true, - undefined, - ), - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier('localStorage', valueType), - true, - undefined, - ), - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID, valueType), - true, - undefined, - ), - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.PARAMSLAMBDA, valueType), - true, - undefined, - ), - arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(InteroperAbilityNames.EXTRAINFO, valueType), - true, - undefined, - ), + arkts.factory + .createETSParameterExpression( + arkts.factory.createIdentifier(InteroperAbilityNames.PARENT, valueType), + true, + undefined + ), + arkts.factory + .createETSParameterExpression( + arkts.factory.createIdentifier(InteroperAbilityNames.PARAM, valueType), + true, + undefined + ), + arkts.factory + .createETSParameterExpression(arkts.factory.createIdentifier('localStorage', valueType), true, undefined), + arkts.factory + .createETSParameterExpression( + arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID, valueType), + true, + undefined + ), + arkts.factory + .createETSParameterExpression( + arkts.factory.createIdentifier(InteroperAbilityNames.PARAMSLAMBDA, valueType), + true, + undefined + ), + arkts.factory + .createETSParameterExpression( + arkts.factory.createIdentifier(InteroperAbilityNames.EXTRAINFO, valueType), + true, + undefined + ), ], flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - }) - return arkts.factory.updateMethodDefinition( - node, - node.kind, - node.id, - arkts.factory.createFunctionExpression(node.id?.clone(), script), - node.modifiers, - false, - node.overloads - ); + }); + const scriptExpr = arkts.factory.createFunctionExpression(undefined, script) + return arkts.factory.updateMethodDefinition(node, node.kind, node.id, scriptExpr, node.modifiers, false); } collectComponentMembers(node: arkts.ETSStructDeclaration, className: string): Map { @@ -286,9 +269,12 @@ export class LegacyTransformer extends AbstractVisitor { enter(node: arkts.AstNode): void { if ((arkts.isETSStructDeclaration(node) || arkts.isClassDeclaration(node)) && !!node.definition.ident) { - const isComponent = node.definition.annotations.some(annotation => arkts.isIdentifier(annotation.expr) && - (annotation.expr.name === 'Component' || annotation.expr.name === 'ComponentV2')); - const scopeInfo: ScopeInfo = { name: node.definition.ident.name, isComponent: isComponent}; + const isComponent = node.definition.annotations.some( + (annotation) => + annotation.expr instanceof arkts.Identifier && + (annotation.expr.name === 'Component' || annotation.expr.name === 'ComponentV2') + ); + const scopeInfo: ScopeInfo = { name: node.definition.ident.name, isComponent: isComponent }; this.scopeInfos.push(scopeInfo); } } @@ -305,12 +291,15 @@ export class LegacyTransformer extends AbstractVisitor { } handleWrappedBuilderNode(node: arkts.ETSTypeReference): arkts.ETSTypeReference { - if (node.part && arkts.isETSTypeReferencePart(node.part) && node.part.name && - arkts.isIdentifier(node.part.name) && node.part.name.name === 'WrappedBuilder') { + if ( + node.part && + arkts.isETSTypeReferencePart(node.part) && + node.part.name && + arkts.isIdentifier(node.part.name) && + node.part.name.name === 'WrappedBuilder' + ) { return arkts.factory.createETSTypeReference( - arkts.factory.createETSTypeReferencePart( - arkts.factory.createIdentifier('Any') - ) + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Any')) ); } return node; @@ -321,8 +310,11 @@ export class LegacyTransformer extends AbstractVisitor { if (arkts.isIdentifier(node.id) && node.id.typeAnnotation) { let typeAnnotation = node.id.typeAnnotation; // WrappedBuilder<[aa]>[] => Any[] - if (arkts.isTSArrayType(typeAnnotation) && typeAnnotation.elementType && - arkts.isETSTypeReference(typeAnnotation.elementType)) { + if ( + arkts.isTSArrayType(typeAnnotation) && + typeAnnotation.elementType && + arkts.isETSTypeReference(typeAnnotation.elementType) + ) { return arkts.factory.updateVariableDeclarator( node, node.flag, @@ -363,19 +355,29 @@ export class LegacyTransformer extends AbstractVisitor { if (arkts.isETSStructDeclaration(newNode) || arkts.isClassDeclaration(newNode)) { const definition = newNode.definition!; const annotations = definition.annotations; - if (annotations.some(annotation => annotation.expr instanceof arkts.Identifier && - (annotation.expr.name === 'Component' || annotation.expr.name === 'ComponentV2'))) { + if ( + annotations.some( + (annotation) => + annotation.expr instanceof arkts.Identifier && + (annotation.expr.name === 'Component' || annotation.expr.name === 'ComponentV2') + ) + ) { const className = newNode.definition?.ident?.name!; const memberMap = this.collectComponentMembers(newNode as arkts.ETSStructDeclaration, className); - this.componentInterfaceCollection.push(this.generateComponentInterface(className, node.modifiers, memberMap)); + this.componentInterfaceCollection.push( + this.generateComponentInterface(className, node.modifiers, memberMap) + ); const updateNode = this.processComponent(newNode); this.exit(newNode); return updateNode; } return newNode; } - if (this.scopeInfos.length > 0 && this.scopeInfos[this.scopeInfos.length - 1].isComponent === true && - arkts.isMethodDefinition(newNode)) { + if ( + this.scopeInfos.length > 0 && + this.scopeInfos[this.scopeInfos.length - 1].isComponent === true && + arkts.isMethodDefinition(newNode) + ) { const kind = newNode.kind; if (kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR) { const updateNode = this.processConstructor(newNode); @@ -387,4 +389,4 @@ export class LegacyTransformer extends AbstractVisitor { } return newNode; } -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/ui-plugins/interop/predefines.ts b/ui2abc/arkui-plugins/ui-plugins/interop/predefines.ts index 2c5d6c1bf5fc6fb27b36242706b9aae655bfb7d7..03b6f99b57c74162ac1e2a65780ed6b7b25cf1b5 100644 --- a/ui2abc/arkui-plugins/ui-plugins/interop/predefines.ts +++ b/ui2abc/arkui-plugins/ui-plugins/interop/predefines.ts @@ -13,7 +13,6 @@ * limitations under the License. */ - export enum InteroperAbilityNames { ARKTS_1_1 = '1.1', ARKTS_1_2 = '1.2', @@ -41,7 +40,6 @@ export enum InteroperAbilityNames { INTEROP = 'arkui.component.interop', } - export enum ESValueMethodNames { ESVALUE = 'ESValue', INITEMPTYOBJECT = 'instantiateEmptyObject', @@ -77,7 +75,7 @@ export enum BuilderParams { PARAM_WRAPPED_KEY = 'param_wrapped_key', INSTANCEPARAM = 'instanceParam', PARAM_WRAPPED = 'param_wrapped', - PARAM_WRAPPED_IT = 'param_wrapped_it' + PARAM_WRAPPED_IT = 'param_wrapped_it', } export const GLOBAL_ANNOTATION_MODULE = 'dynamic/@ohos.arkui.GlobalAnnotation'; diff --git a/ui2abc/arkui-plugins/ui-plugins/interop/utils.ts b/ui2abc/arkui-plugins/ui-plugins/interop/utils.ts index 8a0bc1fc4ee44d4bf2d7f3bdb93d8cdabf7c3137..07bcef198af0418be0b2f5832677ac091a815a34 100644 --- a/ui2abc/arkui-plugins/ui-plugins/interop/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/interop/utils.ts @@ -13,24 +13,16 @@ * limitations under the License. */ - - import * as arkts from '@koalaui/libarkts'; -import { - BuilderMethodNames, - ESValueMethodNames, - InteroperAbilityNames, - GLOBAL_ANNOTATION_MODULE -} from './predefines'; +import { BuilderMethodNames, ESValueMethodNames, InteroperAbilityNames, GLOBAL_ANNOTATION_MODULE } from './predefines'; import { LANGUAGE_VERSION, DecoratorNames } from '../../common/predefines'; import { FileManager } from '../../common/file-manager'; import { BuilderLambdaNames } from '../utils'; import { ImportCollector } from '../../common/import-collector'; - /** - * - * @param result + * + * @param result * @returns let result = ESValue.instantiateEmptyObject() */ export function createEmptyESValue(result: string): arkts.VariableDeclaration { @@ -53,14 +45,14 @@ export function createEmptyESValue(result: string): arkts.VariableDeclaration { false, false ) - ) + ), ] ); } /** - * - * @param value + * + * @param value * @returns ESValue.wrap(value) */ export function getWrapValue(value: arkts.Expression): arkts.Expression { @@ -80,10 +72,10 @@ export function getWrapValue(value: arkts.Expression): arkts.Expression { } /** - * - * @param object - * @param key - * @param value + * + * @param object + * @param key + * @param value * @returns object.setProperty(key, value) */ export function setPropertyESValue(object: string, key: string, value: arkts.Expression): arkts.ExpressionStatement { @@ -96,10 +88,7 @@ export function setPropertyESValue(object: string, key: string, value: arkts.Exp false, false ), - [ - arkts.factory.createStringLiteral(key), - value.clone() - ], + [arkts.factory.createStringLiteral(key), value.clone()], undefined, false, false @@ -108,10 +97,10 @@ export function setPropertyESValue(object: string, key: string, value: arkts.Exp } /** - * - * @param result - * @param obj - * @param key + * + * @param result + * @param obj + * @param key * @returns let result = object.getProperty(key) */ export function getPropertyESValue(result: string, obj: string, key: string): arkts.VariableDeclaration { @@ -134,13 +123,13 @@ export function getPropertyESValue(result: string, obj: string, key: string): ar false, false ) - ) + ), ] ); } /** - * + * * @param {string} stateVarName - Original state variable name to be proxied. * @returns {string} Proxied variable name in the format: "__Proxy_{stateVarName}". */ @@ -150,44 +139,50 @@ export function stateProxy(stateVarName: string): string { /** * get elmtId - * @returns + * @returns * let viewStackProcessor = global.getProperty("ViewStackProcessor"); * let createId = viewStackProcessor.getProperty("AllocateNewElmetIdForNextComponent"); * let elmtId = createId.invoke(); */ export function createELMTID(): arkts.Statement[] { const body: arkts.Statement[] = []; - const viewStackProcessor = getPropertyESValue('viewStackProcessor', InteroperAbilityNames.GLOBAL, 'ViewStackProcessor'); + const viewStackProcessor = getPropertyESValue( + 'viewStackProcessor', + InteroperAbilityNames.GLOBAL, + 'ViewStackProcessor' + ); body.push(viewStackProcessor); const createId = getPropertyESValue('createId', 'viewStackProcessor', 'AllocateNewElmetIdForNextComponent'); body.push(createId); const elmtId = arkts.factory.createVariableDeclaration( arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, - [arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, - arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID), - arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - arkts.factory.createIdentifier('createId'), - arkts.factory.createIdentifier(ESValueMethodNames.INVOKE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, + arkts.factory.createIdentifier(InteroperAbilityNames.ELMTID), + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier('createId'), + arkts.factory.createIdentifier(ESValueMethodNames.INVOKE), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [], + undefined, false, false - ), - [], - undefined, - false, - false - ) - )] + ) + ), + ] ); body.push(elmtId); return body; } /** - * - * @param componentName + * + * @param componentName * @returns return { * component: component, * name: componentName, @@ -195,53 +190,58 @@ export function createELMTID(): arkts.Statement[] { */ export function createInitReturn(componentName: string): arkts.ReturnStatement { return arkts.factory.createReturnStatement( - arkts.factory.createObjectExpression([ - arkts.Property.create1Property( - arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, - arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT), - arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT), - false, - false - ), - arkts.Property.create1Property( - arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, - arkts.factory.createIdentifier('name'), - arkts.factory.createStringLiteral(componentName), - false, - false - ) - ]), + arkts.ObjectExpression.createObjectExpression( + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + [ + arkts.Property.create1Property( + arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, + arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT), + arkts.factory.createIdentifier(InteroperAbilityNames.COMPONENT), + false, + false + ), + arkts.Property.create1Property( + arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, + arkts.factory.createIdentifier('name'), + arkts.factory.createStringLiteral(componentName), + false, + false + ), + ], + false + ) ); } /** - * createGlobal + * createGlobal * @returns let global = ESValue.getGlobal(); */ export function createGlobal(): arkts.Statement { return arkts.factory.createVariableDeclaration( arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, - [arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, - arkts.factory.createIdentifier(InteroperAbilityNames.GLOBAL), - arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - arkts.factory.createIdentifier(ESValueMethodNames.ESVALUE), - arkts.factory.createIdentifier('getGlobal'), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, + arkts.factory.createIdentifier(InteroperAbilityNames.GLOBAL), + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier(ESValueMethodNames.ESVALUE), + arkts.factory.createIdentifier('getGlobal'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [], + undefined, false, false - ), - [], - undefined, - false, - false - ) - )] + ) + ), + ] ); } - export function isInstantiateImpl(node: arkts.MemberExpression): boolean { const property = node.property; if (arkts.isIdentifier(property) && property.name === BuilderLambdaNames.ORIGIN_METHOD_NAME) { @@ -259,20 +259,32 @@ export function isArkTS1_1(node: arkts.MemberExpression): boolean { return true; } +export function insertInteropComponentImports(): void { + ImportCollector.getInstance().collectSource(InteroperAbilityNames.ARKUICOMPATIBLE, InteroperAbilityNames.INTEROP); + ImportCollector.getInstance().collectImport(InteroperAbilityNames.ARKUICOMPATIBLE); + ImportCollector.getInstance().collectSource( + InteroperAbilityNames.GETCOMPATIBLESTATE, + InteroperAbilityNames.INTEROP + ); + ImportCollector.getInstance().collectImport(InteroperAbilityNames.GETCOMPATIBLESTATE); + ImportCollector.getInstance().collectSource( + BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER, + InteroperAbilityNames.INTEROP + ); + ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER); + ImportCollector.getInstance().collectSource( + BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER, + InteroperAbilityNames.INTEROP + ); + ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER); +} + export function isInteropComponent(node: arkts.CallExpression): boolean { if ( arkts.isMemberExpression(node.callee) && isInstantiateImpl(node.callee) && isArkTS1_1(node.callee) ) { - ImportCollector.getInstance().collectSource(InteroperAbilityNames.ARKUICOMPATIBLE, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(InteroperAbilityNames.ARKUICOMPATIBLE); - ImportCollector.getInstance().collectSource(InteroperAbilityNames.GETCOMPATIBLESTATE, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(InteroperAbilityNames.GETCOMPATIBLESTATE); - ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEBUILDER); - ImportCollector.getInstance().collectSource(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER, InteroperAbilityNames.INTEROP); - ImportCollector.getInstance().collectImport(BuilderMethodNames.TRANSFERCOMPATIBLEUPDATABLEBUILDER); return true; } return false; @@ -287,11 +299,11 @@ function isDecoratorAnnotation( return false; } if (!ignoreDecl) { - const decl = arkts.getDecl(anno.expr); + const decl = arkts.getPeerIdentifierDecl(anno.expr.peer); if (!decl) { return false; } - const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + const moduleName = arkts.getProgramFromAstNode(decl)?.moduleName; if (!moduleName || moduleName !== GLOBAL_ANNOTATION_MODULE) { return false; } @@ -312,4 +324,4 @@ export function hasDecoratorInterop( return property.function.annotations.some((anno) => isDecoratorAnnotation(anno, decoratorName)); } return property.annotations.some((anno) => isDecoratorAnnotation(anno, decoratorName)); -} \ No newline at end of file +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/base.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/base.ts new file mode 100644 index 0000000000000000000000000000000000000000..d34d271897fa6455601a3fb7c8efa2e37866443b --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/base.ts @@ -0,0 +1,50 @@ +/* + * 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 { NodeCacheNames } from '../../common/predefines'; +import { AstNodeCacheValueMetadata, NodeCache, NodeCacheFactory } from '../../common/node-cache'; + +export interface BaseCacheInfo { + node: T; + metadata?: AstNodeCacheValueMetadata; +} + +export class BaseMemoCollectCache> { + protected _infos: Info[] = []; + + protected _updateInfo(info: Info): void { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(info.node, info.metadata); + } + + get infos(): Info[] { + return this._infos; + } + + collect(info: Info): void { + this._infos.push(info); + } + + updateAll(): this { + this._infos.forEach((info) => { + this._updateInfo(info); + }); + return this; + } + + reset(): void { + this._infos = []; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-lambda/initialbuilderLambdaBodyCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-lambda/initialbuilderLambdaBodyCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad2ec5a522221102320717a77ef140f186244c12 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-lambda/initialbuilderLambdaBodyCache.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 { BaseCacheInfo, BaseMemoCollectCache } from '../base'; + +export interface InitialBuilderLambdaBodyInfo extends BaseCacheInfo {} + +export class InitialBuilderLambdaBodyCache extends BaseMemoCollectCache< + arkts.Identifier | arkts.CallExpression, + InitialBuilderLambdaBodyInfo +> { + private static instance: InitialBuilderLambdaBodyCache | null = null; + + static getInstance(): InitialBuilderLambdaBodyCache { + if (!this.instance) { + this.instance = new InitialBuilderLambdaBodyCache(); + } + return this.instance; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/classPropertyValueCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/classPropertyValueCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec58f08d41c3468393ad106fafc99a80366a3998 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/classPropertyValueCache.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 { BaseCacheInfo, BaseMemoCollectCache } from '../base'; + +export interface BuilderParamClassPropertyValueInfo extends BaseCacheInfo {} + +export class BuilderParamClassPropertyValueCache extends BaseMemoCollectCache< + arkts.Expression, + BuilderParamClassPropertyValueInfo +> { + private static instance: BuilderParamClassPropertyValueCache | null = null; + + static getInstance(): BuilderParamClassPropertyValueCache { + if (!this.instance) { + this.instance = new BuilderParamClassPropertyValueCache(); + } + return this.instance; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/propertyCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/propertyCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..6fcb293da5e3c9b7a2bc0ac48e8ccc20926a4e9e --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/builder-param/propertyCache.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 { BaseCacheInfo, BaseMemoCollectCache } from '../base'; + +export interface BuilderParamPropertyInfo extends BaseCacheInfo {} + +export class BuilderParamPropertyCache extends BaseMemoCollectCache { + private static instance: BuilderParamPropertyCache | null = null; + + static getInstance(): BuilderParamPropertyCache { + if (!this.instance) { + this.instance = new BuilderParamPropertyCache(); + } + return this.instance; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/condition-scope/conditionScopeInfoCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/condition-scope/conditionScopeInfoCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..87285da55c006574090d8fa7c8feb3eadd31c06f --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/condition-scope/conditionScopeInfoCache.ts @@ -0,0 +1,70 @@ +/* + * 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 { NodeCacheNames } from '../../../common/predefines'; +import { NodeCache, NodeCacheFactory } from '../../../common/node-cache'; + +export interface ConditionScopeInfo { + arg: arkts.ArrowFunctionExpression; + call: arkts.CallExpression; +} + +export class ConditionScopeInfoCache { + private _infos: ConditionScopeInfo[] = []; + private static instance: ConditionScopeInfoCache | null = null; + + static getInstance(): ConditionScopeInfoCache { + if (!this.instance) { + this.instance = new ConditionScopeInfoCache(); + } + return this.instance; + } + + private _updateConditionArg(arg: arkts.ArrowFunctionExpression): void { + const scriptFunc = arg.function; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).addNodeToUpdateByPeer(scriptFunc.peer); + const body = scriptFunc.body; + if (!!body) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).addNodeToUpdateByPeer(body.peer); + } + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(arg); + } + + private _updateConditionCall(call: arkts.CallExpression): void { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(call); + } + + get infos(): ConditionScopeInfo[] { + return this._infos; + } + + collect(info: ConditionScopeInfo): this { + this._infos.push(info); + return this; + } + + updateAll(): this { + this._infos.forEach((info) => { + this._updateConditionArg(info.arg); + this._updateConditionCall(info.call); + }); + return this; + } + + reset(): void { + this._infos = []; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerBuilderCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerBuilderCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e304d309034efe1072742e8ec39323a8ed3eb0a --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerBuilderCache.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 { NodeCacheNames } from '../../../common/predefines'; +import { NodeCache, NodeCacheFactory } from '../../../common/node-cache'; + +export interface customDialogControllerBuilderInfo { + arrowFunc: arkts.ArrowFunctionExpression; + call?: arkts.CallExpression; +} + +export class CustomDialogControllerBuilderCache { + private _infos: customDialogControllerBuilderInfo[] = []; + private static instance: CustomDialogControllerBuilderCache | null = null; + + static getInstance(): CustomDialogControllerBuilderCache { + if (!this.instance) { + this.instance = new CustomDialogControllerBuilderCache(); + } + return this.instance; + } + + private _updateBuilderArrowFunc(arrowFunc: arkts.ArrowFunctionExpression): void { + const scriptFunc = arrowFunc.function; + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).addNodeToUpdateByPeer(scriptFunc.peer); + const body = scriptFunc.body; + if (!!body) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).addNodeToUpdateByPeer(body.peer); + } + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(arrowFunc); + } + + private _updateBuilderCall(call?: arkts.CallExpression): void { + if (!call) { + return; + } + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(call); + } + + get infos(): customDialogControllerBuilderInfo[] { + return this._infos; + } + + collect(info: customDialogControllerBuilderInfo): this { + this._infos.push(info); + return this; + } + + updateAll(): this { + this._infos.forEach((info) => { + this._updateBuilderArrowFunc(info.arrowFunc); + this._updateBuilderCall(info.call); + }); + return this; + } + + reset(): void { + this._infos = []; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..0db339109c8084d4d32a04727065e15866854242 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/custom-dialog/customDialogControllerCache.ts @@ -0,0 +1,68 @@ +/* + * 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 { NodeCacheNames } from '../../../common/predefines'; +import { NodeCache, NodeCacheFactory } from '../../../common/node-cache'; + +export interface CustomDialogControllerInfo { + controller: arkts.ETSNewClassInstanceExpression; +} + +export class CustomDialogControllerCache { + private _infos: CustomDialogControllerInfo[] = []; + private static instance: CustomDialogControllerCache | null = null; + + static getInstance(): CustomDialogControllerCache { + if (!this.instance) { + this.instance = new CustomDialogControllerCache(); + } + return this.instance; + } + + private _updateController(controller: arkts.ETSNewClassInstanceExpression): void { + if (!NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldUpdateByPeer(controller.peer)) { + return; + } + let currParent: arkts.AstNode | undefined = controller.parent; + while ( + !!currParent && + !NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldUpdateByPeer(currParent.peer) + ) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).addNodeToUpdateByPeer(currParent.peer); + currParent = currParent.parent; + } + } + + get infos(): CustomDialogControllerInfo[] { + return this._infos; + } + + collect(info: CustomDialogControllerInfo): this { + this._infos.push(info); + return this; + } + + updateAll(): this { + this._infos.forEach((info) => { + this._updateController(info.controller); + }); + return this; + } + + reset(): void { + this._infos = []; + } +} \ No newline at end of file diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/index.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..57c27d83e81d23f24bfb30579427fee10ea112c8 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/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 './builder-param/propertyCache'; +export * from './builder-param/classPropertyValueCache'; +export * from './condition-scope/conditionScopeInfoCache'; +export * from './builder-lambda/initialbuilderLambdaBodyCache'; +export * from './property/propertyFactoryCallTypeCache'; +export * from './custom-dialog/customDialogControllerCache'; +export * from './custom-dialog/customDialogControllerBuilderCache'; \ No newline at end of file diff --git a/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/property/propertyFactoryCallTypeCache.ts b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/property/propertyFactoryCallTypeCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..85bc345518a677af2abeeeec49f491ababfa0fbc --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/memo-collect-cache/property/propertyFactoryCallTypeCache.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 { BaseCacheInfo, BaseMemoCollectCache } from '../base'; + +interface PropertyFactoryCallTypeInfo extends BaseCacheInfo {} + +export class PropertyFactoryCallTypeCache extends BaseMemoCollectCache { + private static instance: PropertyFactoryCallTypeCache | null = null; + + static getInstance(): PropertyFactoryCallTypeCache { + if (!this.instance) { + this.instance = new PropertyFactoryCallTypeCache(); + } + return this.instance; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/namespace-processor.ts b/ui2abc/arkui-plugins/ui-plugins/namespace-processor.ts index d590b71d53682c4a0095fc74a055168382c6f33d..9dd7bd0c42c6d66a7cc5dc9b4839ac5143d4ffb0 100644 --- a/ui2abc/arkui-plugins/ui-plugins/namespace-processor.ts +++ b/ui2abc/arkui-plugins/ui-plugins/namespace-processor.ts @@ -62,4 +62,3 @@ export class NamespaceProcessor { return arkts.factory.updateETSModule(node, [...node.statements, ...this.currentNamepaceInterfaces], node.ident, node.getNamespaceFlag(), node.program); } } - \ No newline at end of file diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/base.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/base.ts index 903585dbed101cd1d1f469cfaafd364c4ea5cf59..604c5d97eec50c1c5b822d5bde57415b0f1b21e3 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/base.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/base.ts @@ -14,35 +14,78 @@ */ import * as arkts from '@koalaui/libarkts'; -import { collectStateManagementTypeImport, createGetter, createSetter } from './utils'; -import { CustomComponentInfo, ClassInfo } from '../utils'; -import { StateManagementTypes } from '../../common/predefines'; +import { + collectStateManagementTypeImport, + createGetter, + createSetter, + createSetter2, + findCachedMemoMetadata, + generateGetOrSetCall, + generateThisBacking, + hasDecoratorName, + removeDecorator, + removeImplementProperty, +} from './utils'; +import { StructInfo, ClassInfo } from '../utils'; +import { + CustomComponentNames, + DecoratorNames, + GetSetTypes, + NodeCacheNames, + ObservedNames, + StateManagementTypes, +} from '../../common/predefines'; import { ClassScopeInfo } from '../struct-translators/utils'; import { logDiagnostic, getPropertyType } from '../interop/initstatevar'; import { getHasAnnotationObserved } from '../interop/interop'; -import { NodeCache } from '../../common/node-cache'; +import { + CustomComponentInterfacePropertyInfo, + NormalClassMethodInfo, + NormalClassPropertyInfo, + StructMethodInfo, + StructPropertyInfo, +} from '../../collectors/ui-collectors/records'; +import { factory } from './factory'; +import { PropertyCache } from './cache/propertyCache'; +import { annotation, backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; +import { factory as UIFactory } from '../ui-factory'; +import { CustomDialogControllerPropertyCache } from './cache/customDialogControllerPropertyCache'; +import { PropertyFactoryCallTypeCache } from '../memo-collect-cache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export interface PropertyTranslatorOptions { +export interface BasePropertyTranslatorOptions { property: arkts.ClassProperty; - structInfo: CustomComponentInfo; } -export abstract class PropertyTranslator { +export abstract class BasePropertyTranslator { + protected stateManagementType: StateManagementTypes | undefined; protected property: arkts.ClassProperty; - protected structInfo: CustomComponentInfo; protected propertyType: arkts.TypeNode | undefined; protected isMemoCached?: boolean; + protected hasWatch?: boolean; + protected makeType?: StateManagementTypes; + protected hasInitializeStruct?: boolean; + protected hasUpdateStruct?: boolean; + protected hasToRecord?: boolean; + protected hasField?: boolean; + protected hasGetter?: boolean; + protected hasSetter?: boolean; + protected shouldWrapPropertyType?: boolean; - constructor(options: PropertyTranslatorOptions) { + constructor(options: BasePropertyTranslatorOptions) { this.property = options.property; - this.structInfo = options.structInfo; - this.checkObservedWhenInterop(options.property, options.structInfo); this.propertyType = options.property.typeAnnotation?.clone(); - this.isMemoCached = NodeCache.getInstance().has(options.property); + this.isMemoCached = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(options.property); } - checkObservedWhenInterop(property: arkts.ClassProperty, structInfo: CustomComponentInfo): void { - if (structInfo.annotations.component) { + abstract translateMember(): arkts.AstNode[]; + + protected _checkObservedWhenInterop( + property: arkts.ClassProperty, + hasComponent?: boolean, + hasComponentV2?: boolean + ): void { + if (!!hasComponent) { const isObservedV2From1_1 = getHasAnnotationObserved(property, 'ObservedV2'); if (isObservedV2From1_1) { let decoratorType = 'regular'; @@ -51,7 +94,7 @@ export abstract class PropertyTranslator { logDiagnostic(errorMessage, property); } } - if (structInfo.annotations.componentV2) { + if (!!hasComponentV2) { const isObservedFrom1_1 = getHasAnnotationObserved(property, 'Observed'); if (isObservedFrom1_1) { let decoratorType = 'regular'; @@ -62,60 +105,510 @@ export abstract class PropertyTranslator { } } - abstract translateMember(): arkts.AstNode[]; + protected cacheTranslatedInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): void {} + + protected translateWithoutInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.AstNode[] { + const nodes: arkts.AstNode[] = []; + if (this.hasField) { + nodes.push(this.field(newName, originalName, metadata)); + } + if (this.hasGetter) { + nodes.push(this.getter(newName, originalName, metadata)); + } + if (this.hasSetter) { + nodes.push(this.setter(newName, originalName, metadata)); + } + return nodes; + } + + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + const field: arkts.ClassProperty = factory.createOptionalClassProperty( + newName, + this.property, + this.stateManagementType, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(field, metadata); + } + return field; + } + + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const getter: arkts.MethodDefinition = createGetter( + originalName, + this.propertyType, + thisGet, + this.isMemoCached, + false, + metadata + ); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(getter, metadata); + } + return getter; + } - translateGetter( + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const setter: arkts.MethodDefinition = createSetter2(originalName, this.propertyType, thisSet); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(setter, metadata); + } + return setter; + } + + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.MemberExpression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; + } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + factory.generateInitializeValue(this.property, this.propertyType, originalName), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); + } + collectStateManagementTypeImport(this.stateManagementType); + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); } - translateSetter( + updateStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - left: arkts.MemberExpression - ): arkts.MethodDefinition { - const right: arkts.CallExpression = arkts.factory.createCallExpression( - arkts.factory.createIdentifier(StateManagementTypes.OBSERVABLE_PROXY), - [arkts.factory.createIdentifier('value')], - undefined, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + if (!this.propertyType) { + return undefined; + } + + const mutableThis: arkts.Expression = generateThisBacking(newName); + const member: arkts.MemberExpression = arkts.factory.createMemberExpression( + arkts.factory.createTSNonNullExpression(mutableThis), + arkts.factory.createIdentifier(StateManagementTypes.UPDATE), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, false, false ); - collectStateManagementTypeImport(StateManagementTypes.OBSERVABLE_PROXY); - return createSetter(originalName, typeAnnotation, left, right); + const propertyType = this.propertyType.clone(); + const asExpression = arkts.factory.createTSAsExpression( + factory.createNonNullOrOptionalMemberExpression( + CustomComponentNames.COMPONENT_INITIALIZERS_NAME, + originalName, + false, + true + ), + propertyType, + false + ); + if (this.isMemoCached) { + PropertyFactoryCallTypeCache.getInstance().collect({ node: propertyType, metadata }); + } + return factory.createIfInUpdateStruct(originalName, member, [asExpression]); + } + + toRecord(originalName: string): arkts.Property { + return arkts.factory.createProperty( + arkts.Es2pandaPropertyKind.PROPERTY_KIND_INIT, + arkts.factory.createStringLiteral(originalName), + arkts.factory.createBinaryExpression( + arkts.factory.createMemberExpression( + arkts.factory.createIdentifier('paramsCasted'), + arkts.factory.createIdentifier(originalName), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + arkts.ETSNewClassInstanceExpression.createETSNewClassInstanceExpression( + arkts.factory.createETSTypeReference( + arkts.factory.createETSTypeReferencePart(arkts.factory.createIdentifier('Object')) + ), + [] + ), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING + ), + false, + false + ); + } +} + +export interface PropertyTranslatorOptions extends BasePropertyTranslatorOptions { + structInfo: StructInfo; +} + +export abstract class PropertyTranslator extends BasePropertyTranslator { + protected structInfo: StructInfo; + + constructor(options: PropertyTranslatorOptions) { + super(options); + this.structInfo = options.structInfo; + this.checkObservedWhenInterop(this.property, this.structInfo); + } + + checkObservedWhenInterop(property: arkts.ClassProperty, structInfo: StructInfo): void { + const hasComponent = !!structInfo.annotations.component; + const hasComponentV2 = !!structInfo.annotations.componentV2; + this._checkObservedWhenInterop(property, hasComponent, hasComponentV2); + } + + translateMember(): arkts.AstNode[] { + const originalName: string = expectName(this.property.key); + const newName: string = backingField(originalName); + const shouldWrapPropertyType = + this.shouldWrapPropertyType || (!!this.propertyType && arkts.isETSTypeReference(this.propertyType)); + const metadata = this.isMemoCached ? findCachedMemoMetadata(this.property, shouldWrapPropertyType) : undefined; + this.cacheTranslatedInitializer(newName, originalName, metadata); + return this.translateWithoutInitializer(newName, originalName, metadata); + } + + protected cacheTranslatedInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): void { + const structName: string = this.structInfo.name; + if (this.hasInitializeStruct) { + const initializeStruct = this.initializeStruct(newName, originalName, metadata); + if (initializeStruct) { + PropertyCache.getInstance().collectInitializeStruct(structName, [initializeStruct]); + } + } + if (this.hasUpdateStruct) { + const updateStruct = this.updateStruct(newName, originalName, metadata); + if (updateStruct) { + PropertyCache.getInstance().collectUpdateStruct(structName, [updateStruct]); + } + } + if (this.hasToRecord && !!this.structInfo.annotations?.reusable) { + const toRecord = this.toRecord(originalName); + PropertyCache.getInstance().collectToRecord(structName, [toRecord]); + } + } +} + +export interface PropertyCachedTranslatorOptions extends BasePropertyTranslatorOptions { + propertyInfo: StructPropertyInfo; +} + +export abstract class PropertyCachedTranslator extends BasePropertyTranslator { + protected propertyInfo: StructPropertyInfo; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.propertyInfo = options.propertyInfo; + this.checkObservedWhenInterop(options.property, options.propertyInfo); + this.collectCustomDialogControllerProperty(); + } + + collectCustomDialogControllerProperty(): void { + if (!this.propertyInfo.structInfo?.annotationInfo?.hasCustomDialog || !this.propertyInfo.structInfo?.name) { + return; + } + if (!this.propertyType) { + return; + } + CustomDialogControllerPropertyCache.getInstance().collect( + this.property, + this.propertyType, + this.propertyInfo.structInfo.name + ); + } + + checkObservedWhenInterop(property: arkts.ClassProperty, propertyInfo: StructPropertyInfo): void { + const hasComponent = !!propertyInfo.structInfo?.annotationInfo?.hasComponent; + const hasComponentV2 = !!propertyInfo.structInfo?.annotationInfo?.hasComponentV2; + this._checkObservedWhenInterop(property, hasComponent, hasComponentV2); + } + + translateMember(): arkts.AstNode[] { + if (!this.propertyInfo || !this.propertyInfo.structInfo || !this.propertyInfo.name) { + return []; + } + const originalName = this.propertyInfo.name; + const newName: string = backingField(originalName); + const shouldWrapPropertyType = + this.shouldWrapPropertyType || (!!this.propertyType && arkts.isETSTypeReference(this.propertyType)); + const metadata = this.isMemoCached ? findCachedMemoMetadata(this.property, shouldWrapPropertyType) : undefined; + this.cacheTranslatedInitializer(newName, originalName, metadata); + const res = this.translateWithoutInitializer(newName, originalName, metadata); + return res; } + + protected cacheTranslatedInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): void { + if (!this.propertyInfo?.structInfo?.name) { + return; + } + const structName: string = this.propertyInfo.structInfo.name; + if (this.hasInitializeStruct) { + const initializeStruct = this.initializeStruct(newName, originalName, metadata); + if (initializeStruct) { + PropertyCache.getInstance().collectInitializeStruct(structName, [initializeStruct]); + } + } + if (this.hasUpdateStruct) { + const updateStruct = this.updateStruct(newName, originalName, metadata); + if (updateStruct) { + PropertyCache.getInstance().collectUpdateStruct(structName, [updateStruct]); + } + } + if (this.hasToRecord && !!this.propertyInfo.structInfo.annotationInfo?.hasReusable) { + const toRecord = this.toRecord(originalName); + PropertyCache.getInstance().collectToRecord(structName, [toRecord]); + } + } +} + +export interface BaseMethodTranslatorOptions { + method: arkts.MethodDefinition; } -export abstract class MethodTranslator { +export abstract class BaseMethodTranslator { protected method: arkts.MethodDefinition; - protected classInfo: ClassInfo; protected returnType: arkts.TypeNode | undefined; - constructor(method: arkts.MethodDefinition, classInfo: ClassInfo) { - this.method = method; - this.classInfo = classInfo; - this.returnType = this.method.function!.returnTypeAnnotation?.clone(); + constructor(options: BaseMethodTranslatorOptions) { + this.method = options.method; + this.returnType = this.method.function.returnTypeAnnotation?.clone(); } abstract translateMember(): arkts.AstNode[]; } -export abstract class ObservedPropertyTranslator { - protected property: arkts.ClassProperty; - protected classScopeInfo: ClassScopeInfo; - protected propertyType: arkts.TypeNode | undefined; +export interface MethodTranslatorOptions extends BaseMethodTranslatorOptions { + classInfo: ClassInfo; +} + +export abstract class MethodTranslator extends BaseMethodTranslator { + protected classInfo: ClassInfo; + + constructor(options: MethodTranslatorOptions) { + super(options); + this.classInfo = options.classInfo; + } +} + +export interface MethodCacheTranslatorOptions extends BaseMethodTranslatorOptions { + methodInfo: StructMethodInfo | NormalClassMethodInfo; +} + +export abstract class MethodCacheTranslator extends BaseMethodTranslator { + protected methodInfo: StructMethodInfo | NormalClassMethodInfo; + + constructor(options: MethodCacheTranslatorOptions) { + super(options); + this.methodInfo = options.methodInfo; + } +} + +export interface BaseObservedPropertyTranslatorOptions { + property: arkts.ClassProperty; +} + +export interface IBaseObservedPropertyTranslator { + traceDecorator?: DecoratorNames.TRACE | DecoratorNames.TRACK; + property?: arkts.ClassProperty; + propertyType?: arkts.TypeNode | undefined; + propertyModifier?: arkts.Es2pandaModifierFlags; +} + +export abstract class BaseObservedPropertyTranslator implements IBaseObservedPropertyTranslator { + property: arkts.ClassProperty; + propertyType: arkts.TypeNode | undefined; + traceDecorator?: DecoratorNames.TRACE | DecoratorNames.TRACK; + propertyModifier?: arkts.Es2pandaModifierFlags; + protected hasImplement?: boolean; + protected hasBackingField?: boolean; + protected hasMetaField?: boolean; + protected hasGetterSetter?: boolean; - constructor(property: arkts.ClassProperty, classScopeInfo: ClassScopeInfo) { - this.property = property; - this.classScopeInfo = classScopeInfo; - this.propertyType = property.typeAnnotation; + constructor(options: BaseObservedPropertyTranslatorOptions) { + this.property = options.property; + this.propertyType = options.property.typeAnnotation; + this.hasImplement = expectName(this.property.key).startsWith(ObservedNames.PROPERTY_PREFIX); } abstract translateMember(): arkts.AstNode[]; - abstract createField(originalName: string, newName: string): arkts.ClassProperty[]; + + backingField(originalName: string, newName: string): arkts.ClassProperty { + const backingField = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(newName), + this.property.value, + this.propertyType, + this.propertyModifier ?? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + if (!this.property.value) { + backingField.modifiers |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; + } + const annotations: arkts.AnnotationUsage[] = [...this.property.annotations]; + if ( + !hasDecoratorName(this.property, DecoratorNames.JSONSTRINGIFYIGNORE) && + !hasDecoratorName(this.property, DecoratorNames.JSONRENAME) + ) { + annotations.push( + annotation(DecoratorNames.JSONRENAME).addProperty( + arkts.factory.createClassProperty( + arkts.factory.createIdentifier(ObservedNames.NEW_NAME), + arkts.factory.createStringLiteral(originalName), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + false + ) + ) + ); + } + backingField.setAnnotations(annotations); + removeDecorator(backingField, this.traceDecorator!); + return backingField; + } + + metaField(originalName: string, newName: string): arkts.ClassProperty { + collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META); + const metaField = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(`${StateManagementTypes.META}_${originalName}`), + factory.generateStateMgmtFactoryCall(StateManagementTypes.MAKE_MUTABLESTATE_META, undefined, [], false), + UIFactory.createTypeReferenceFromString(StateManagementTypes.MUTABLE_STATE_META), + this.propertyModifier ?? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + return metaField; + } + + abstract getter(originalName: string, newName: string): arkts.MethodDefinition; + + abstract setter(originalName: string, newName: string): arkts.MethodDefinition; +} + +export interface ObservedPropertyTranslatorOptions extends BaseObservedPropertyTranslatorOptions { + classScopeInfo: ClassScopeInfo; +} + +export abstract class ObservedPropertyTranslator extends BaseObservedPropertyTranslator { + protected classScopeInfo: ClassScopeInfo; + + constructor(options: ObservedPropertyTranslatorOptions) { + super(options); + this.classScopeInfo = options.classScopeInfo; + } + + translateMember(): arkts.AstNode[] { + const originalName: string = this.hasImplement + ? removeImplementProperty(expectName(this.property.key)) + : expectName(this.property.key); + const newName: string = backingField(originalName); + const fields: arkts.AstNode[] = []; + if (this.hasBackingField) { + fields.push(this.backingField(originalName, newName)); + } + if (this.hasMetaField) { + fields.push(this.metaField(originalName, newName)); + } + if (this.hasGetterSetter) { + this.cacheGetterSetter(originalName, newName); + } + return fields; + } + + protected cacheGetterSetter(originalName: string, newName: string): void { + const newGetter = this.getter(originalName, newName); + const newSetter = this.setter(originalName, newName); + if (this.hasImplement) { + { + const idx: number = this.classScopeInfo.getters.findIndex( + (getter) => getter.id!.name === originalName + ); + const originGetter: arkts.MethodDefinition = this.classScopeInfo.getters[idx]; + const originSetter: arkts.MethodDefinition = originGetter.overloads[0]; + const updateGetter: arkts.MethodDefinition = arkts.factory.updateMethodDefinition( + originGetter, + originGetter.kind, + newGetter.key, + arkts.factory.createFunctionExpression( + undefined, + newGetter.function.addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD), + ), + originGetter.modifiers, + false + ); + arkts.factory.updateMethodDefinition( + originSetter, + originSetter.kind, + newSetter.key, + arkts.factory.createFunctionExpression( + undefined, + newSetter.function + .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_OVERLOAD) + .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD), + ), + originSetter.modifiers, + false + ); + this.classScopeInfo.getters[idx] = updateGetter; + } + } else { + this.classScopeInfo.getters.push(...[newGetter, newSetter]); + } + } +} + +export interface ObservedPropertyCachedTranslatorOptions extends BaseObservedPropertyTranslatorOptions { + propertyInfo: NormalClassPropertyInfo; +} + +export abstract class ObservedPropertyCachedTranslator extends BaseObservedPropertyTranslator { + protected propertyInfo: NormalClassPropertyInfo; + + constructor(options: ObservedPropertyCachedTranslatorOptions) { + super(options); + this.propertyInfo = options.propertyInfo; + } + + translateMember(): arkts.AstNode[] { + if (!this.propertyInfo) { + return [this.property]; + } + const fields: arkts.AstNode[] = []; + const name: string = this.propertyInfo.name!; + const originalName: string = this.hasImplement ? removeImplementProperty(name) : name; + const newName: string = backingField(originalName); + if (this.hasBackingField) { + fields.push(this.backingField(originalName, newName)); + } + if (this.hasMetaField) { + fields.push(this.metaField(originalName, newName)); + } + if (!this.hasImplement) { + fields.push(this.getter(originalName, newName), this.setter(originalName, newName)); + } + return fields; + } } export type InterfacePropertyTypes = arkts.MethodDefinition | arkts.ClassProperty; @@ -127,6 +620,8 @@ export interface InterfacePropertyTranslatorOptions implements InterfacePropertyTranslatorOptions { + protected decorator: DecoratorNames | undefined; + property: T; modified: boolean; @@ -136,9 +631,73 @@ export abstract class InterfacePropertyTranslator | undefined`. + * + * @param method expecting getter with decorator. + */ + protected updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + if (!this.decorator) { + throw new Error('interface property does not have any decorator.'); + } + const metadata = findCachedMemoMetadata(method); + return factory.wrapStateManagementTypeToMethodInInterface(method, this.decorator, metadata); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `StateManagementType | undefined`. + * + * @param property expecting property with decorator. + */ + protected updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + if (!this.decorator) { + throw new Error('interface property does not have any decorator.'); + } + return factory.wrapStateManagementTypeToPropertyInInterface(property, this.decorator); + } static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { return false; } } + +export interface InterfacePropertyCachedTranslatorOptions + extends InterfacePropertyTranslatorOptions { + propertyInfo?: CustomComponentInterfacePropertyInfo; +} + +export abstract class InterfacePropertyCachedTranslator + extends InterfacePropertyTranslator + implements InterfacePropertyCachedTranslatorOptions +{ + propertyInfo?: CustomComponentInterfacePropertyInfo; + + constructor(options: InterfacePropertyCachedTranslatorOptions) { + super(options); + this.propertyInfo = options.propertyInfo; + } + + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return false; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/builderParam.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/builderParam.ts index 4f0d9c871073d9e1ac2173d562abd8f40dc4a4fe..efbee193284e590a4cb311f59f42b3211070ef35 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/builderParam.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/builderParam.ts @@ -15,117 +15,216 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames } from '../../common/predefines'; +import { backingField, coerceToAstNode, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; +import { DecoratorNames, NodeCacheNames } from '../../common/predefines'; import { createGetter, createSetter, generateThisBacking, hasDecorator, removeDecorator } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyTranslator, +} from './base'; import { factory } from './factory'; import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../../collectors/memo-collectors/utils'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { CacheFactory as BuilderLambdaCacheFactory } from '../builder-lambda-translators/cache-factory'; +import { BuilderParamClassPropertyValueCache } from '../memo-collect-cache'; import { PropertyCache } from './cache/propertyCache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export class BuilderParamTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithBuilderLambdaProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + rewriteFn?: (node: T) => T +): arkts.Statement | undefined { + const mutableThis: arkts.Expression = generateThisBacking(newName); + let value = this.property.value ?? arkts.factory.createUndefinedLiteral(); + if (!!value && arkts.isArrowFunctionExpression(value)) { + value = rewriteFn?.(value) ?? value; + BuilderParamClassPropertyValueCache.getInstance().collect({ node: value }); } + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + mutableThis, + arkts.factory.createBinaryExpression( + arkts.factory.createBinaryExpression( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier('initializers'), + originalName + ), + arkts.factory.createIdentifier('content'), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING + ), + value, + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING + ), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); +} - cacheTranslatedInitializer(newName: string, originalName: string): void { - const mutableThis: arkts.Expression = generateThisBacking(newName); - const initializeStruct: arkts.Statement = this.generateInitializeStruct(mutableThis, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); +function fieldWithBuilderLambdaProperty( + this: BasePropertyTranslator, + fieldFn: (name: string) => arkts.ClassProperty, + newName: string +): arkts.ClassProperty { + if ( + !!this.propertyType && + (arkts.isETSFunctionType(this.propertyType) || arkts.isETSUnionType(this.propertyType)) + ) { + addMemoAnnotation(this.propertyType); } + const field = fieldFn(newName); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(field); + return field; +} + +function getterWithBuilderLambdaProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string +): arkts.MethodDefinition { + const getter: arkts.MethodDefinition = createGetter( + originalName, + this.propertyType, + arkts.hasModifierFlag(this.property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL) + ? generateThisBacking(newName, false, false) + : generateThisBacking(newName, false, true), + true + ); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(getter); + return getter; +} - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const propertyType = this.propertyType; - if (!!propertyType && (arkts.isETSFunctionType(propertyType) || arkts.isETSUnionType(propertyType))) { - addMemoAnnotation(propertyType); +function setterWithBuilderLambdaProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string +): arkts.MethodDefinition { + const thisSetValue: arkts.Expression = generateThisBacking(newName, false, false); + const right: arkts.Identifier = arkts.factory.createIdentifier('value'); + const setter: arkts.MethodDefinition = createSetter(originalName, this.propertyType, thisSetValue, right, true); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(setter); + return setter; +} + +function updateStateMethodInInterface( + this: InterfacePropertyTranslator, + method: arkts.MethodDefinition +): arkts.MethodDefinition { + if (!this.decorator) { + throw new Error('interface property does not have any decorator.'); + } + if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + const type: arkts.TypeNode | undefined = method.function.returnTypeAnnotation; + if (!!type && (arkts.isETSFunctionType(type) || arkts.isETSUnionType(type))) { + addMemoAnnotation(type); + } + removeDecorator(method, this.decorator); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method, { isGetter: true }); + } else if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + const param = method.function.params[0] as arkts.ETSParameterExpression; + const type = param.typeAnnotation; + if (!!type && (arkts.isETSFunctionType(type) || arkts.isETSUnionType(type))) { + addMemoAnnotation(type); } - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - true - ); - arkts.MemoNodeCache.getInstance().collect(field); - const thisSetValue: arkts.Expression = generateThisBacking(newName, false, false); - const getter: arkts.MethodDefinition = this.translateGetter( - originalName, - propertyType, - arkts.hasModifierFlag(this.property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL) - ? generateThisBacking(newName, false, false) - : generateThisBacking(newName, false, true) - ); - arkts.MemoNodeCache.getInstance().collect(getter); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, propertyType?.clone(), thisSetValue); - arkts.MemoNodeCache.getInstance().collect(setter); - - return [field, getter, setter]; - } - - translateGetter( + removeDecorator(method, this.decorator); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(method, { isSetter: true }); + } + return method; +} + +function updateStatePropertyInInterface( + this: InterfacePropertyTranslator, + property: arkts.ClassProperty +): arkts.ClassProperty { + if (!this.decorator) { + throw new Error('interface property does not have any decorator.'); + } + const type: arkts.TypeNode | undefined = property.typeAnnotation; + if (findCanAddMemoFromTypeAnnotation(type)) { + addMemoAnnotation(type); + } + removeDecorator(property, this.decorator); + return property; +} + +export class BuilderParamTranslator extends PropertyTranslator { + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue, true); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithBuilderLambdaProperty.bind(this)(newName, originalName); + } + + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + return fieldWithBuilderLambdaProperty.bind(this)(super.field.bind(this), newName); + } + + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return getterWithBuilderLambdaProperty.bind(this)(newName, originalName); + } + + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return setterWithBuilderLambdaProperty.bind(this)(newName, originalName); } +} - translateSetter( +export class BuilderParamCachedTranslator extends PropertyCachedTranslator { + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - left: arkts.Expression - ): arkts.MethodDefinition { - const right: arkts.Identifier = arkts.factory.createIdentifier('value'); - return createSetter(originalName, typeAnnotation, left, right, true); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + const rewriteFn = (node: T): T => { + const _node = coerceToAstNode(node); + return BuilderLambdaCacheFactory.updateBuilderArrowFunction(_node) as arkts.AstNode as T; + }; + return initializeStructWithBuilderLambdaProperty.bind(this)(newName, originalName, rewriteFn); } - generateInitializeStruct(mutableThis: arkts.Expression, originalName: string): arkts.Statement { - const value = this.property.value; - if (!!value && arkts.isArrowFunctionExpression(value)) { - arkts.MemoNodeCache.getInstance().collect(value); - } - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - mutableThis, - arkts.factory.createBinaryExpression( - arkts.factory.createBinaryExpression( - factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier('initializers'), - originalName - ), - arkts.factory.createIdentifier('content'), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING - ), - value ?? arkts.factory.createUndefinedLiteral(), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + return fieldWithBuilderLambdaProperty.bind(this)(super.field.bind(this), newName); + } + + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return getterWithBuilderLambdaProperty.bind(this)(newName, originalName); + } + + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return setterWithBuilderLambdaProperty.bind(this)(newName, originalName); } } export class BuilderParamInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateBuilderParamMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateBuilderParamPropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.BUILDER_PARAM; + /** + * @deprecated + */ 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; } @@ -135,24 +234,8 @@ export class BuilderParamInterfaceTranslator e * * @param method expecting getter with `@BuilderParam` and a setter with `@BuilderParam` in the overloads. */ - private updateBuilderParamMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { - const type: arkts.TypeNode | undefined = method.function!.returnTypeAnnotation; - if (!!type && (arkts.isETSFunctionType(type) || arkts.isETSUnionType(type))) { - addMemoAnnotation(type); - } - removeDecorator(method, DecoratorNames.BUILDER_PARAM); - arkts.MemoNodeCache.getInstance().collect(method, { isGetter: true }); - } else if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { - const param = method.function!.params.at(0)! as arkts.ETSParameterExpression; - const type = param.typeAnnotation; - if (!!type && (arkts.isETSFunctionType(type) || arkts.isETSUnionType(type))) { - addMemoAnnotation(type); - } - removeDecorator(method, DecoratorNames.BUILDER_PARAM); - arkts.MemoNodeCache.getInstance().collect(method, { isSetter: true }); - } - return method; + updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return updateStateMethodInInterface.bind(this)(method); } /** @@ -160,12 +243,41 @@ export class BuilderParamInterfaceTranslator e * * @param property expecting property with `@BuilderParam`. */ - private updateBuilderParamPropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - const type: arkts.TypeNode | undefined = property.typeAnnotation; - if (findCanAddMemoFromTypeAnnotation(type)) { - addMemoAnnotation(type); - } - removeDecorator(property, DecoratorNames.BUILDER_PARAM); - return property; + updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return updateStatePropertyInInterface.bind(this)(property); + } +} + +export class BuilderParamCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.BUILDER_PARAM; + + /** + * @deprecated + */ + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.annotationInfo?.hasBuilderParam; + } + + /** + * Add `@memo` to getter's return type and setter's param type (expecting a function type or a function type within a union type). + * + * @param method expecting getter with `@BuilderParam` and a setter with `@BuilderParam` in the overloads. + */ + updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return updateStateMethodInInterface.bind(this)(method); + } + + /** + * Add `@memo` to the type of the property (expecting a function type or a function type within a union type). + * + * @param property expecting property with `@BuilderParam`. + */ + updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return updateStatePropertyInInterface.bind(this)(property); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/cache-factory.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..b85742dc89718b549a26a194925c460e615d9d68 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache-factory.ts @@ -0,0 +1,204 @@ +/* + * 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 { NormalClassMethodInfo, StructMethodInfo } from '../../collectors/ui-collectors/records'; +import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; +import { DecoratorNames, GetSetTypes, ObservedNames, StateManagementTypes } from '../../common/predefines'; +import { backingField } from '../../common/arkts-utils'; +import { factory as UIFactory } from '../ui-factory'; +import { generateThisBacking, removeDecorator } from './utils'; +import { factory } from './factory'; +import { + getterBodyWithObservedTrackProperty, + IObservedTrackTranslator, + setterIfEqualsNewValueWithObservedTrackProperty, +} from './observedTrack'; +import { + getterBodyWithObservedV2TraceProperty, + IObservedV2TraceTranslator, + setterIfEqualsNewValueWithObservedV2TraceProperty, +} from './observedV2Trace'; +import { MonitorCacheTranslator } from './monitor'; +import { PropertyRewriteCache } from './cache/propertyRewriteCache'; +import { ComputedCacheTranslator } from './computed'; + +export class CacheFactory { + /** + * add `@memo` to the `@Builder` methods in class. + */ + static addMemoToBuilderClassMethodFromInfo( + method: arkts.MethodDefinition, + metadata: StructMethodInfo + ): arkts.MethodDefinition { + if (metadata.annotationInfo?.hasBuilder) { + removeDecorator(method, DecoratorNames.BUILDER); + addMemoAnnotation(method.function); + } + return method; + } + + static transformObservedImplementsMethodFromInfo( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + getterSetterType?: GetSetTypes + ): arkts.MethodDefinition { + if (!metadata.name || !getterSetterType) { + return node; + } + const rewriteOptions: IObservedTrackTranslator = { + traceDecorator: DecoratorNames.TRACK, + isTracked: !!metadata.inheritPorpertyInfo?.annotationInfo?.hasTrack, + }; + if (getterSetterType === GetSetTypes.GET) { + return this.createTrackGet(node, metadata, rewriteOptions); + } + if (getterSetterType === GetSetTypes.SET) { + return this.createTrackSet(node, metadata, rewriteOptions); + } + return node; + } + + static createTrackGet( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + rewriteOptions: IObservedTrackTranslator + ): arkts.MethodDefinition { + const originalName: string = metadata.name!; + const newName: string = backingField(originalName); + const body = getterBodyWithObservedTrackProperty.bind(rewriteOptions)(originalName, newName); + node.function.setBody(body); + return node; + } + + static createTrackSet( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + rewriteOptions: IObservedTrackTranslator + ): arkts.MethodDefinition { + const originalName: string = metadata.name!; + const newName: string = backingField(originalName); + const scriptFunction = node.function; + const params = scriptFunction.params; + if (params.length <= 0 || !arkts.isETSParameterExpression(params.at(0)!)) { + return node; + } + const originParam: arkts.ETSParameterExpression = params.at(0)! as arkts.ETSParameterExpression; + const type = originParam.typeAnnotation; + if (!type || !arkts.isTypeNode(type)) { + return node; + } + const ifEqualsNewValue = setterIfEqualsNewValueWithObservedTrackProperty.bind(rewriteOptions)( + originalName, + newName + ); + const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); + const param = arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, type), + false, + undefined + ); + scriptFunction.setParams([param]).setBody(body); + return node; + } + + static transformObservedV2ImplementsMethodFromInfo( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + getterSetterType?: GetSetTypes + ): arkts.MethodDefinition { + if (!metadata.name || !metadata.classInfo?.name || !getterSetterType) { + return node; + } + if (node.isStatic) { + return node; + } + const rewriteOptions: IObservedV2TraceTranslator = { + className: metadata.classInfo.name, + traceDecorator: DecoratorNames.TRACE, + isTraced: !!metadata.inheritPorpertyInfo?.annotationInfo?.hasTrace, + }; + if (getterSetterType === GetSetTypes.GET) { + return this.createTraceGet(node, metadata, rewriteOptions); + } + if (getterSetterType === GetSetTypes.SET) { + return this.createTraceSet(node, metadata, rewriteOptions); + } + return node; + } + + static createTraceGet( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + rewriteOptions: IObservedV2TraceTranslator + ): arkts.MethodDefinition { + const originalName: string = metadata.name!; + const newName: string = backingField(originalName); + const body = getterBodyWithObservedV2TraceProperty.bind(rewriteOptions)(originalName, newName); + node.function.setBody(body); + return node; + } + + static createTraceSet( + node: arkts.MethodDefinition, + metadata: NormalClassMethodInfo, + rewriteOptions: IObservedV2TraceTranslator + ): arkts.MethodDefinition { + const originalName: string = metadata.name!; + const newName: string = backingField(originalName); + const scriptFunction = node.function; + const params = scriptFunction.params; + if (params.length <= 0 || !arkts.isETSParameterExpression(params.at(0)!)) { + return node; + } + const originParam: arkts.ETSParameterExpression = params.at(0)! as arkts.ETSParameterExpression; + const type = originParam.typeAnnotation; + if (!type || !arkts.isTypeNode(type)) { + return node; + } + const ifEqualsNewValue = setterIfEqualsNewValueWithObservedV2TraceProperty.bind(rewriteOptions)( + originalName, + newName + ); + const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); + const param = arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, type), + false, + undefined + ); + scriptFunction.setParams([param]).setBody(body); + return node; + } + + static rewriteMonitorMethodFromInfo( + method: arkts.MethodDefinition, + metadata: StructMethodInfo | NormalClassMethodInfo + ): arkts.MethodDefinition { + const monitorTranslator = new MonitorCacheTranslator({ method, methodInfo: metadata }); + const newNodes: arkts.AstNode[] = monitorTranslator.translateMember(); + PropertyRewriteCache.getInstance().collectRewriteNodes(method.peer, newNodes); + return method; + } + + static rewriteComputedMethodFromInfo( + method: arkts.MethodDefinition, + metadata: StructMethodInfo | NormalClassMethodInfo + ): arkts.MethodDefinition { + const computedTranslator = new ComputedCacheTranslator({ method, methodInfo: metadata }); + const newNodes: arkts.AstNode[] = computedTranslator.translateMember(); + PropertyRewriteCache.getInstance().collectRewriteNodes(method.peer, newNodes); + return method; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/customDialogControllerPropertyCache.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/customDialogControllerPropertyCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..b66fb26202212920ed4922a162ac94c2596eab40 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/customDialogControllerPropertyCache.ts @@ -0,0 +1,111 @@ +/* + * 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 { CustomDialogNames } from '../../../common/predefines'; +import { expectNameInTypeReference } from '../../../common/arkts-utils'; +import { isDeclFromArkUI } from '../../../collectors/ui-collectors/utils'; + +export interface CustomDialogControllerPropertyInfo { + propertyName: string; + controllerTypeName: string; +} + +function findCustomDialogControllerTypeName( + node: arkts.TypeNode | undefined, + ignoreDecl: boolean = false +): string | undefined { + if (!node) { + return undefined; + } + if (arkts.isETSUnionType(node)) { + for (const typeNode of node.types) { + const controllerName = findCustomDialogControllerTypeName(typeNode, ignoreDecl); + if (!!controllerName) { + return controllerName; + } + } + return undefined; + } + if (arkts.isETSTypeReference(node)) { + const nameNode = expectNameInTypeReference(node); + if (!nameNode) { + return undefined; + } + const decl = arkts.getPeerIdentifierDecl(nameNode.peer); + if (!decl || !arkts.isClassDefinition(decl)) { + return undefined; + } + if (!ignoreDecl && !isDeclFromArkUI(decl)) { + return undefined; + } + if (nameNode.name === CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) { + return nameNode.name; + } + return undefined; + } + return undefined; +} + +function collectInfoFromProperty( + node: arkts.ClassProperty, + typeNode: arkts.TypeNode | undefined, + ignoreDecl: boolean = false +): CustomDialogControllerPropertyInfo | undefined { + const key = node.key; + if (!key || !arkts.isIdentifier(key) || !typeNode) { + return undefined; + } + const controllerTypeName = findCustomDialogControllerTypeName(typeNode, ignoreDecl); + if (!controllerTypeName) { + return undefined; + } + return { propertyName: key.name, controllerTypeName }; +} + +export class CustomDialogControllerPropertyCache { + private _cache: Map; + private static instance: CustomDialogControllerPropertyCache; + + private constructor() { + this._cache = new Map(); + } + + static getInstance(): CustomDialogControllerPropertyCache { + if (!this.instance) { + this.instance = new CustomDialogControllerPropertyCache(); + } + return this.instance; + } + + reset(): void { + this._cache.clear(); + } + + getInfo(className: string): CustomDialogControllerPropertyInfo | undefined { + return this._cache.get(className); + } + + collect( + property: arkts.ClassProperty, + propertyType: arkts.TypeNode | undefined, + className: string, + ignoreDecl: boolean = false + ): void { + const info = collectInfoFromProperty(property, propertyType, ignoreDecl); + if (!!info) { + this._cache.set(className, info); + } + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyCache.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyCache.ts index 43bc7ca27dc787fb1cbd718811a57233c83616cf..b87119354c6c8063b18a949c8dc01fe5bae403d8 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyCache.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyCache.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; export interface PropertyCachedBody { initializeBody?: arkts.Statement[]; - updateBody?: arkts.AstNode[]; + updateBody?: arkts.Statement[]; toRecordBody?: arkts.Property[]; constructorBody?: arkts.AstNode[]; monitorBody?: arkts.AstNode[]; @@ -45,7 +45,7 @@ export class PropertyCache { return this._cache.get(name)?.initializeBody ?? []; } - getUpdateBody(name: string): arkts.AstNode[] { + getUpdateBody(name: string): arkts.Statement[] { return this._cache.get(name)?.updateBody ?? []; } @@ -59,7 +59,7 @@ export class PropertyCache { this._cache.set(name, { ...this._cache.get(name), initializeBody: newInitializeBody }); } - collectUpdateStruct(name: string, updateStruct: arkts.AstNode[]): void { + collectUpdateStruct(name: string, updateStruct: arkts.Statement[]): void { const updateBody = this._cache.get(name)?.updateBody ?? []; const newUpdateBody = [...updateBody, ...updateStruct]; this._cache.set(name, { ...this._cache.get(name), updateBody: newUpdateBody }); diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyRewriteCache.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyRewriteCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..5fc74224fcc1df79421a33fe06ea5d10cfe6fe01 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/cache/propertyRewriteCache.ts @@ -0,0 +1,46 @@ +/* + * 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 { AstNodePointer } from '../../../common/safe-types'; + +export class PropertyRewriteCache { + private _cache: Map; + private static instance: PropertyRewriteCache; + + private constructor() { + this._cache = new Map(); + } + + static getInstance(): PropertyRewriteCache { + if (!this.instance) { + this.instance = new PropertyRewriteCache(); + } + return this.instance; + } + + reset(): void { + this._cache.clear(); + } + + getRewriteNodes(ptr: AstNodePointer): arkts.AstNode[] { + return this._cache.get(ptr) ?? []; + } + + collectRewriteNodes(ptr: AstNodePointer, nodes: arkts.AstNode[]): void { + const originProperties = this._cache.get(ptr) ?? []; + const newProperties = [...originProperties, ...nodes]; + this._cache.set(ptr, newProperties); + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/computed.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/computed.ts index 3b396c40d72402df2d7ec2a02259a1828be9e4af..c63849db06b12d13fc51e178e93c03f41d1bea45 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/computed.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/computed.ts @@ -17,22 +17,95 @@ import * as arkts from '@koalaui/libarkts'; import { expectName } from '../../common/arkts-utils'; import { GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { checkIsStructMethodFromInfo } from '../../collectors/ui-collectors/utils'; import { ClassInfo, computedField } from '../utils'; import { generateThisBacking, generateGetOrSetCall } from './utils'; -import { MethodTranslator } from './base'; -import { InitializerConstructor } from './types'; +import { + BaseMethodTranslator, + MethodCacheTranslator, + MethodCacheTranslatorOptions, + MethodTranslator, + MethodTranslatorOptions, +} from './base'; import { factory as UIFactory } from '../ui-factory'; import { factory } from './factory'; import { ComputedCache } from './cache/computedCache'; -export class ComputedTranslator extends MethodTranslator implements InitializerConstructor { +function fieldWithComputedMethod( + this: BaseMethodTranslator, + newName: string, + originalName: string, + modifiers: arkts.Es2pandaModifierFlags +): arkts.ClassProperty { + const field: arkts.ClassProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(newName), + factory.generateStateMgmtFactoryCall( + StateManagementTypes.MAKE_COMPUTED, + this.returnType, + [ + arkts.factory.createArrowFunctionExpression( + UIFactory.createScriptFunction({ + body: this.method.function.body?.clone(), + modifiers: modifiers, + flags: + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW | + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN, + }) + ), + arkts.factory.createStringLiteral(originalName), + ], + false + ), + undefined, + modifiers, + false + ); + return field; +} + +function getterWithComputedMethod( + this: BaseMethodTranslator, + newName: string, + className: string, + isStatic: boolean +): arkts.MethodDefinition { + const scriptFunction = this.method.function; + scriptFunction.addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN); + scriptFunction.setBody( + arkts.factory.createBlockStatement([arkts.factory.createReturnStatement(computedGetCall(newName, className, isStatic))]) + ); + return this.method; +} + +function computedGetCall(newName: string, className: string, isStatic: boolean): arkts.CallExpression { + const thisValue: arkts.Expression = isStatic + ? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(className), newName) + : generateThisBacking(newName, false, true); + return generateGetOrSetCall(thisValue, GetSetTypes.GET); +} + +export interface IComputedTranslator { + field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty; + getter(newName: string, isStatic: boolean): arkts.MethodDefinition; +} + +export class ComputedTranslator extends MethodTranslator implements IComputedTranslator { private isStatic: boolean; - constructor(method: arkts.MethodDefinition, classInfo: ClassInfo) { - super(method, classInfo); + constructor(options: MethodTranslatorOptions) { + super(options); this.isStatic = this.method.isStatic; } + field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty { + const modifiers = isStatic ? this.method.modifiers : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + return fieldWithComputedMethod.bind(this)(newName, originalName, modifiers); + } + + getter(newName: string, isStatic: boolean): arkts.MethodDefinition { + return getterWithComputedMethod.bind(this)(newName, this.classInfo.className, isStatic); + } + translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.method.id); const newName: string = computedField(originalName); @@ -47,50 +120,52 @@ export class ComputedTranslator extends MethodTranslator implements InitializerC } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const modifiers = this.isStatic ? this.method.modifiers : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; - const field: arkts.ClassProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_COMPUTED, - this.returnType?.clone(), - [ - arkts.factory.createArrowFunctionExpression( - UIFactory.createScriptFunction({ - body: this.method.function!.body?.clone(), - modifiers: modifiers, - flags: - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW | - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN, - }) - ), - arkts.factory.createStringLiteral(originalName), - ], - false - ), - undefined, - modifiers, - false - ); - - const originGetter: arkts.MethodDefinition = UIFactory.updateMethodDefinition(this.method, { - function: { - returnTypeAnnotation: this.returnType?.clone(), - flags: - this.method.function.flags | - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_HAS_RETURN, - body: arkts.factory.createBlockStatement([ - arkts.factory.createReturnStatement(this.generateComputedGet(newName)), - ]), - }, - }); - - return [field, originGetter]; + const field = this.field(newName, originalName, this.isStatic); + const getter = this.getter(newName, this.isStatic); + return [field, getter]; } +} + +export class ComputedCacheTranslator extends MethodCacheTranslator implements IComputedTranslator { + private isStatic: boolean; - generateComputedGet(newName: string): arkts.CallExpression { - const thisValue: arkts.Expression = this.isStatic - ? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(this.classInfo.className), newName) - : generateThisBacking(newName, false, true); - return generateGetOrSetCall(thisValue, GetSetTypes.GET); + constructor(options: MethodCacheTranslatorOptions) { + super(options); + this.isStatic = this.method.isStatic; + } + + field(newName: string, originalName: string, isStatic: boolean): arkts.ClassProperty { + const modifiers = isStatic ? this.methodInfo.modifiers! : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + return fieldWithComputedMethod.bind(this)(newName, originalName, modifiers); + } + + getter(newName: string, isStatic: boolean): arkts.MethodDefinition { + let className: string; + if (checkIsStructMethodFromInfo(this.methodInfo)) { + className = this.methodInfo.structInfo?.name!; + } else { + className = this.methodInfo.classInfo?.name!; + } + return getterWithComputedMethod.bind(this)(newName, className, isStatic); + } + + translateMember(): arkts.AstNode[] { + const originalName: string = this.methodInfo.name!; + const newName: string = computedField(originalName); + this.cacheTranslatedInitializer(newName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string): void { + if (!checkIsStructMethodFromInfo(this.methodInfo) || this.isStatic) { + return; + } + ComputedCache.getInstance().collectComputed(this.methodInfo.structInfo?.name!, { newName }); + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = this.field(newName, originalName, this.isStatic); + const getter = this.getter(newName, this.isStatic); + return [field, getter]; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/consume.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/consume.ts index fb5602bb2a162a7c499a04b282bc802b96520629..00640a0dcbb9ec1776fe0fe4f82fab40a27c39c6 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/consume.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/consume.ts @@ -16,7 +16,8 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; import { generateToRecord, createGetter, @@ -26,130 +27,139 @@ import { getValueInAnnotation, hasDecorator, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export class ConsumeTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithConsumeProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(originalName, newName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + arkts.factory.createStringLiteral(getValueInAnnotation(this.property, DecoratorNames.CONSUME) ?? originalName), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); } + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.CONSUME_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - arkts.MemoNodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - arkts.MemoNodeCache.getInstance().collect(getter, metadata); - arkts.MemoNodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; +function updateStateMethodInInterface( + this: InterfacePropertyTranslator, + method: arkts.MethodDefinition +): arkts.MethodDefinition { + const metadata = findCachedMemoMetadata(method); + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.CONSUME, metadata); +} + +function updateStatePropertyInInterface( + this: InterfacePropertyTranslator, + property: arkts.ClassProperty +): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.CONSUME); +} + +export class ConsumeTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.CONSUME_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_CONSUME; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateGetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithConsumeProperty.bind(this)(newName, originalName, metadata); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); +export class ConsumeCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.CONSUME_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_CONSUME; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - generateInitializeStruct(originalName: string, newName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - arkts.factory.createStringLiteral( - getValueInAnnotation(this.property, DecoratorNames.CONSUME) ?? originalName - ), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_CONSUME, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithConsumeProperty.bind(this)(newName, originalName, metadata); } } export class ConsumeInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.CONSUME; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.CONSUME); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.CONSUME); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `ConsumeDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Consume` and a setter with `@Consume` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.CONSUME, metadata); - } +export class ConsumeCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.CONSUME; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `ConsumeDecoratedVariable | undefined`. - * - * @param property expecting property with `@Consume`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.CONSUME); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasConsume; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/consumer.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/consumer.ts index 52bc40afdd247e25145d0d06fc584881b51f04b1..12b850a0daeba00e8989f1a43e61d497bf9ccf80 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/consumer.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/consumer.ts @@ -16,7 +16,8 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; import { createGetter, createSetter2, @@ -25,126 +26,117 @@ import { getValueInAnnotation, hasDecorator, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export class ConsumerTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithConsumerProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + arkts.factory.createStringLiteral( + getValueInAnnotation(this.property, DecoratorNames.CONSUMER) ?? originalName + ), + this.property.value!, + ]; + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(originalName, newName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - } +export class ConsumerTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.CONSUMER_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_CONSUMER; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.CONSUMER_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - arkts.MemoNodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - arkts.MemoNodeCache.getInstance().collect(getter, metadata); - arkts.MemoNodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; - } - - translateGetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithConsumerProperty.bind(this)(newName, originalName, metadata); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); +export class ConsumerCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.CONSUMER_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_CONSUMER; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); } - generateInitializeStruct(originalName: string, newName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - arkts.factory.createStringLiteral( - getValueInAnnotation(this.property, DecoratorNames.CONSUMER) ?? originalName - ), - this.property.value!, - ]; - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_CONSUMER, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithConsumerProperty.bind(this)(newName, originalName, metadata); } } export class ConsumerInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.CONSUMER; + /** + * @deprecated + */ static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.CONSUMER)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.CONSUMER)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.CONSUMER); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.CONSUMER); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IConsumerDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Consumer` and a setter with `@Consumer` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.CONSUMER, metadata); - } +export class ConsumerCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.CONSUMER; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IConsumerDecoratedVariable | undefined`. - * - * @param property expecting property with `@Consumer`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.CONSUMER); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasConsumer; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/event.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/event.ts new file mode 100644 index 0000000000000000000000000000000000000000..fcf59656258464256dcaacca9389f840dc896671 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/event.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 { backingField, expectName } from '../../common/arkts-utils'; +import { DecoratorNames, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + createGetter, + generateToRecord, + generateThisBacking, + createSetter2, + isCustomDialogController, + findCachedMemoMetadata, +} from './utils'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyTranslator, +} from './base'; +import { factory } from './factory'; +import { PropertyCache } from './cache/propertyCache'; +import { factory as UIFactory } from '../ui-factory'; +import { CustomComponentNames, optionsHasField } from '../utils'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { + RegularCachedInterfaceTranslator, + RegularInterfaceTranslator, + RegularPropertyCachedTranslator, + RegularPropertyTranslator, +} from './regularProperty'; + +export class EventTranslator extends RegularPropertyTranslator { + protected shouldWrapPropertyType: boolean = false; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; +} + +export class EventCachedTranslator extends RegularPropertyCachedTranslator { + protected shouldWrapPropertyType: boolean = false; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; +} + +export class EventInterfaceTranslator extends RegularInterfaceTranslator {} + +export class EventCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends RegularCachedInterfaceTranslator { + protected decorator: DecoratorNames = DecoratorNames.EVENT; + + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.annotationInfo?.hasEvent; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/factory.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/factory.ts index 457e5594785ee4c16866cffb840e4bf25f0e133c..70bd53438cc6c1e525a3df9e17f72d5b8d73240f 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/factory.ts @@ -22,6 +22,7 @@ import { ObservedNames, MonitorNames, TypeNames, + NodeCacheNames, } from '../../common/predefines'; import { factory as UIFactory } from '../ui-factory'; import { @@ -35,7 +36,8 @@ import { import { CustomComponentNames, optionsHasField } from '../utils'; import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../../collectors/memo-collectors/utils'; import { annotation, isNumeric } from '../../common/arkts-utils'; -import { AstNodeCacheValueMetadata } from '../../common/node-cache'; +import { PropertyFactoryCallTypeCache } from '../memo-collect-cache'; +import { AstNodeCacheValueMetadata, NodeCache, NodeCacheFactory } from '../../common/node-cache'; export class factory { /** @@ -51,58 +53,14 @@ export class factory { info?: OptionalMemberInfo ): arkts.Expression { let id = GenSymGenerator.getInstance().id(key); + const alternate = this.generateConditionalAlternate(id, key, info); const statements: arkts.Statement[] = [ - factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object), - factory.generateTernaryExpression(id, key, info), + UIFactory.generateLetVariableDecl(arkts.factory.createIdentifier(id), object), + UIFactory.generateTernaryExpression(id, alternate), ]; return arkts.factory.createBlockExpression(statements); } - /** - * generate a variable declaration, e.g. `let = `; - * - * @param left left expression. - * @param right right expression. - */ - static generateLetVariableDecl(left: arkts.Identifier, right: arkts.Expression): arkts.VariableDeclaration { - return arkts.factory.createVariableDeclaration( - arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, - [ - arkts.factory.createVariableDeclarator( - arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, - left, - right - ), - ] - ); - } - - /** - * generate a ternary expression, e.g. ` ? : `; - * - * @param testLeft the left hand of the test condition. - * @param key item after ?. - */ - static generateTernaryExpression( - testLeft: string, - key: string, - info?: OptionalMemberInfo - ): arkts.ExpressionStatement { - const test = arkts.factory.createBinaryExpression( - arkts.factory.createIdentifier(testLeft), - arkts.factory.createNullLiteral(), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EQUAL - ); - const consequent: arkts.Expression = arkts.factory.createUndefinedLiteral(); - return arkts.factory.createExpressionStatement( - arkts.factory.createConditionalExpression( - test, - consequent, - this.generateConditionalAlternate(testLeft, key, info) - ) - ); - } - static generateConditionalAlternate(testLeft: string, key: string, info?: OptionalMemberInfo): arkts.Expression { const leftIdent: arkts.Identifier = arkts.factory.createIdentifier(testLeft); const alternate: arkts.MemberExpression = UIFactory.generateMemberExpression( @@ -112,10 +70,10 @@ export class factory { return info?.isCall ? arkts.factory.createCallExpression(alternate, [], undefined, false, false) : info?.isNumeric - ? arkts.factory.createCallExpression(alternate, [ - arkts.factory.createNumberLiteral(Number(key)), - ], undefined, false, false) - : alternate; + ? arkts.factory.createCallExpression(alternate, [ + arkts.factory.createNumberLiteral(Number(key)), + ], undefined, false, false) + : alternate; } /** @@ -130,9 +88,10 @@ export class factory { ): arkts.Expression { let id = GenSymGenerator.getInstance().id(key1); let initial: arkts.Expression = factory.createBlockStatementForOptionalExpression(object, key1); + const alternate = this.generateConditionalAlternate(id, key2); const statements: arkts.Statement[] = [ - factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), initial), - factory.generateTernaryExpression(id, key2), + UIFactory.generateLetVariableDecl(arkts.factory.createIdentifier(id), initial), + UIFactory.generateTernaryExpression(id, alternate), ]; return arkts.factory.createBlockExpression(statements); } @@ -267,7 +226,7 @@ export class factory { ): arkts.CallExpression { collectStateManagementTypeImport(StateManagementTypes.STATE_MANAGEMENT_FACTORY); if (!!typeArguments && !!memoMetadata) { - arkts.MemoNodeCache.getInstance().collect(typeArguments, memoMetadata); + PropertyFactoryCallTypeCache.getInstance().collect({ node: typeArguments, metadata: memoMetadata }); } return arkts.factory.createCallExpression( UIFactory.generateMemberExpression( @@ -318,12 +277,10 @@ export class factory { ); } - static judgeIfAddWatchFunc(args: arkts.Expression[], property: arkts.ClassProperty): void { - if (hasDecorator(property, DecoratorNames.WATCH)) { - const watchStr: string | undefined = getValueInAnnotation(property, DecoratorNames.WATCH); - if (watchStr) { - args.push(factory.createWatchCallback(watchStr)); - } + static addWatchFunc(args: arkts.Expression[], property: arkts.ClassProperty): void { + const watchStr: string | undefined = getValueInAnnotation(property, DecoratorNames.WATCH); + if (watchStr) { + args.push(factory.createWatchCallback(watchStr)); } } @@ -336,7 +293,7 @@ export class factory { ): arkts.ClassProperty { const originType = property.typeAnnotation; const newType: arkts.TypeNode | undefined = !stageManagementType - ? property.typeAnnotation ?? UIFactory.createTypeReferenceFromString(TypeNames.ANY) + ? (property.typeAnnotation ?? UIFactory.createTypeReferenceFromString(TypeNames.ANY)) : originType; if (needMemo && findCanAddMemoFromTypeAnnotation(newType)) { addMemoAnnotation(newType); @@ -379,7 +336,10 @@ export class factory { arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, false ); - subscribedWatches.setAnnotations([annotation(DecoratorNames.JSONSTRINGIFYIGNORE), annotation(DecoratorNames.JSONPARSEIGNORE)]); + subscribedWatches.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); collectStateManagementTypeImport(StateManagementTypes.SUBSCRIBED_WATCHES); const addWatchSubscriber = factory.createWatchMethod( @@ -503,7 +463,10 @@ export class factory { arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, false ); - v1RenderId.setAnnotations([annotation(DecoratorNames.JSONSTRINGIFYIGNORE), annotation(DecoratorNames.JSONPARSEIGNORE)]); + v1RenderId.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); collectStateManagementTypeImport(StateManagementTypes.RENDER_ID_TYPE); const setV1RenderId: arkts.MethodDefinition = factory.setV1RenderId(isObservedV2); return isObservedV2 ? [setV1RenderId] : [v1RenderId, setV1RenderId]; @@ -618,7 +581,10 @@ export class factory { arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, false ); - meta.setAnnotations([annotation(DecoratorNames.JSONSTRINGIFYIGNORE), annotation(DecoratorNames.JSONPARSEIGNORE)]); + meta.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); return meta; } @@ -727,7 +693,7 @@ export class factory { if (!!param && !!(wrapTypeName = DECORATOR_TYPE_MAP.get(decoratorName))) { newParam = factory.wrapInterfacePropertyParamExpr(param, wrapTypeName); if (!!metadata) { - arkts.MemoNodeCache.getInstance().collect(newParam, metadata); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newParam, metadata); } collectStateManagementTypeImport(wrapTypeName); } @@ -754,7 +720,7 @@ export class factory { removeDecorator(method, decorator); if (!!newType) { if (!!metadata) { - arkts.MemoNodeCache.getInstance().collect(newType, metadata); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(newType, metadata); } func.setReturnTypeAnnotation(newType); } @@ -828,7 +794,7 @@ export class factory { monitorItem: string[] | undefined, originalName: string, newName: string, - isFromStruct: boolean, + isFromStruct: boolean ): arkts.ExpressionStatement { const thisValue: arkts.Expression = generateThisBacking(newName, false, false); const args: arkts.Expression[] = [this.generatePathArg(monitorItem), this.generateLambdaArg(originalName)]; @@ -943,9 +909,18 @@ export class factory { } static generateComputedOwnerAssignment(newName: string): arkts.ExpressionStatement { - const computedVariable = UIFactory.generateMemberExpression(arkts.factory.createThisExpression(), newName, false); - const setOwnerFunc = UIFactory.generateMemberExpression(computedVariable, StateManagementTypes.SET_OWNER, false); + const computedVariable = UIFactory.generateMemberExpression( + arkts.factory.createThisExpression(), + newName, + false + ); + const setOwnerFunc = UIFactory.generateMemberExpression( + computedVariable, + StateManagementTypes.SET_OWNER, + false + ); return arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(setOwnerFunc, [arkts.factory.createThisExpression()], undefined, false, false)); + arkts.factory.createCallExpression(setOwnerFunc, [arkts.factory.createThisExpression()], undefined, false, false) + ); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/index.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/index.ts index a77fc891347dfc0d9d09e47bf324125b7c630345..b6a6f29c59d4c87aa07be7f9934110786bfe8477 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/index.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/index.ts @@ -15,52 +15,145 @@ import * as arkts from '@koalaui/libarkts'; +import { + CustomComponentInterfacePropertyInfo, + NormalClassAnnotationInfo, + NormalClassPropertyInfo, + StructPropertyAnnotationInfo, + StructPropertyInfo, +} from '../../collectors/ui-collectors/records'; import { DecoratorNames } from '../../common/predefines'; -import { InterfacePropertyTranslator, MethodTranslator, PropertyTranslator } from './base'; +import { + PropertyCachedTranslator, + InterfacePropertyTranslator, + MethodTranslator, + PropertyTranslator, + InterfacePropertyCachedTranslator, + BaseObservedPropertyTranslator, + InterfacePropertyTypes, + BaseMethodTranslator, +} from './base'; import { hasDecorator } from './utils'; -import { StateInterfaceTranslator, StateTranslator } from './state'; -import { StorageLinkInterfaceTranslator, StorageLinkTranslator } from './storagelink'; -import { LocalStorageLinkInterfaceTranslator, LocalStorageLinkTranslator } from './localstoragelink'; -import { LinkInterfaceTranslator, LinkTranslator } from './link'; -import { ObjectLinkInterfaceTranslator, ObjectLinkTranslator } from './objectlink'; -import { RegularInterfaceTranslator, RegularPropertyTranslator } from './regularProperty'; -import { StaticPropertyTranslator } from './staticProperty'; -import { CustomComponentInfo } from '../utils'; -import { ConsumeInterfaceTranslator, ConsumeTranslator } from './consume'; -import { ProvideInterfaceTranslator, ProvideTranslator } from './provide'; -import { BuilderParamInterfaceTranslator, BuilderParamTranslator } from './builderParam'; -import { PropRefInterfaceTranslator, PropRefTranslator } from './propRef'; -import { ObservedTrackTranslator } from './observedTrack'; +import { + StateCachedInterfaceTranslator, + StateCachedTranslator, + StateTranslator, + StateInterfaceTranslator, +} from './state'; +import { + StorageLinkCachedTranslator, + StorageLinkCachedInterfaceTranslator, + StorageLinkTranslator, + StorageLinkInterfaceTranslator, +} from './storagelink'; +import { + LocalStorageLinkCachedTranslator, + LocalStorageLinkCachedInterfaceTranslator, + LocalStorageLinkTranslator, + LocalStorageLinkInterfaceTranslator, +} from './localstoragelink'; +import { LinkCachedTranslator, LinkCachedInterfaceTranslator, LinkTranslator, LinkInterfaceTranslator } from './link'; +import { + ObjectLinkCachedTranslator, + ObjectLinkTranslator, + ObjectLinkInterfaceTranslator, + ObjectLinkCachedInterfaceTranslator, +} from './objectlink'; +import { + RegularPropertyCachedTranslator, + RegularCachedInterfaceTranslator, + RegularPropertyTranslator, + RegularInterfaceTranslator, +} from './regularProperty'; +import { StaticPropertyCachedTranslator, StaticPropertyTranslator } from './staticProperty'; +import { ClassInfo, StructInfo } from '../utils'; +import { + ConsumeCachedTranslator, + ConsumeCachedInterfaceTranslator, + ConsumeTranslator, + ConsumeInterfaceTranslator, +} from './consume'; +import { + ProvideCachedTranslator, + ProvideCachedInterfaceTranslator, + ProvideTranslator, + ProvideInterfaceTranslator, +} from './provide'; +import { + BuilderParamCachedTranslator, + BuilderParamCachedInterfaceTranslator, + BuilderParamTranslator, + BuilderParamInterfaceTranslator, +} from './builderParam'; +import { + PropRefCachedTranslator, + PropRefCachedInterfaceTranslator, + PropRefTranslator, + PropRefInterfaceTranslator, +} from './propRef'; +import { ObservedTrackCachedTranslator, ObservedTrackTranslator } from './observedTrack'; import { ClassScopeInfo } from '../struct-translators/utils'; -import { LocalInterfaceTranslator, LocalTranslator } from './local'; -import { StoragePropRefInterfaceTranslator, StoragePropRefTranslator } from './storagePropRef'; -import { LocalStoragePropRefInterfaceTranslator, LocalStoragePropRefTranslator } from './localStoragePropRef'; -import { ObservedV2TraceTranslator } from './observedV2Trace'; -import { ParamInterfaceTranslator, ParamTranslator } from './param'; -import { OnceInterfaceTranslator, OnceTranslator } from './once'; -import { ProviderInterfaceTranslator, ProviderTranslator } from './provider'; -import { ConsumerInterfaceTranslator, ConsumerTranslator } from './consumer'; +import { + LocalCachedTranslator, + LocalCachedInterfaceTranslator, + LocalTranslator, + LocalInterfaceTranslator, +} from './local'; +import { + StoragePropRefCachedTranslator, + StoragePropRefCachedInterfaceTranslator, + StoragePropRefTranslator, + StoragePropRefInterfaceTranslator, +} from './storagePropRef'; +import { + LocalStoragePropRefCachedTranslator, + LocalStoragePropRefCachedInterfaceTranslator, + LocalStoragePropRefTranslator, + LocalStoragePropRefInterfaceTranslator, +} from './localStoragePropRef'; +import { ObservedV2TraceCachedTranslator, ObservedV2TraceTranslator } from './observedV2Trace'; +import { + ParamCachedTranslator, + ParamCachedInterfaceTranslator, + ParamTranslator, + ParamInterfaceTranslator, +} from './param'; +import { OnceCachedTranslator, OnceCachedInterfaceTranslator, OnceTranslator, OnceInterfaceTranslator } from './once'; +import { + ProviderCachedTranslator, + ProviderCachedInterfaceTranslator, + ProviderTranslator, + ProviderInterfaceTranslator, +} from './provider'; +import { + ConsumerCachedTranslator, + ConsumerCachedInterfaceTranslator, + ConsumerTranslator, + ConsumerInterfaceTranslator, +} from './consumer'; import { ComputedTranslator } from './computed'; import { MonitorTranslator } from './monitor'; +import { EventCachedInterfaceTranslator, EventCachedTranslator } from './event'; +import { RequireCachedTranslator } from './require'; -export { PropertyTranslator, InterfacePropertyTranslator }; +export { BaseObservedPropertyTranslator, PropertyTranslator, PropertyCachedTranslator, InterfacePropertyTranslator }; export type { ClassScopeInfo }; export function classifyStructMembers( member: arkts.AstNode, - structInfo: CustomComponentInfo + structInfo: StructInfo ): PropertyTranslator | MethodTranslator | undefined { if (arkts.isClassProperty(member)) { return classifyProperty(member, structInfo); } else if (arkts.isMethodDefinition(member)) { - return classifyMethod(member, true, structInfo.name); + return classifyMethod(member, { isFromStruct: true, className: structInfo.name }); } return undefined; } export function classifyProperty( property: arkts.AstNode, - structInfo: CustomComponentInfo + structInfo: StructInfo ): PropertyTranslator | undefined { if (!arkts.isClassProperty(property)) return undefined; if (StaticPropertyTranslator.canBeStaticTranslate(property)) { @@ -83,7 +176,7 @@ export function classifyProperty( export function classifyV1Property( property: arkts.ClassProperty, - structInfo: CustomComponentInfo + structInfo: StructInfo ): PropertyTranslator | undefined { if (hasDecorator(property, DecoratorNames.STATE)) { return new StateTranslator({ property, structInfo }); @@ -127,7 +220,7 @@ export function classifyV1Property( export function classifyV2Property( property: arkts.ClassProperty, - structInfo: CustomComponentInfo + structInfo: StructInfo ): PropertyTranslator | undefined { if (hasDecorator(property, DecoratorNames.LOCAL)) { return new LocalTranslator({ property, structInfo }); @@ -223,34 +316,28 @@ export function classifyV2PropertyInInterface(property: arkts.AstNode): Interfac return undefined; } -export type ObservedTranslator = ObservedV2TraceTranslator | ObservedTrackTranslator; - export function classifyObservedClassProperty( - member: arkts.ClassProperty, + property: arkts.ClassProperty, classScopeInfo: ClassScopeInfo -): ObservedTranslator | undefined { +): BaseObservedPropertyTranslator | undefined { if (classScopeInfo.isObservedV2) { - return new ObservedV2TraceTranslator(member, classScopeInfo); + return new ObservedV2TraceTranslator({ property, classScopeInfo }); } if (classScopeInfo.isObserved || classScopeInfo.classHasTrack) { - return new ObservedTrackTranslator(member, classScopeInfo); + return new ObservedTrackTranslator({ property, classScopeInfo }); } return undefined; } -export function classifyMethod( - member: arkts.AstNode, - isFromStruct: boolean, - className: string -): MethodTranslator | undefined { - if (!arkts.isMethodDefinition(member)) { +export function classifyMethod(method: arkts.AstNode, classInfo: ClassInfo): MethodTranslator | undefined { + if (!arkts.isMethodDefinition(method)) { return undefined; } - if (hasDecorator(member, DecoratorNames.COMPUTED)) { - return new ComputedTranslator(member, { isFromStruct, className }); + if (hasDecorator(method, DecoratorNames.COMPUTED)) { + return new ComputedTranslator({ method, classInfo }); } - if (hasDecorator(member, DecoratorNames.MONITOR)) { - return new MonitorTranslator(member, { isFromStruct, className }); + if (hasDecorator(method, DecoratorNames.MONITOR)) { + return new MonitorTranslator({ method, classInfo }); } return undefined; } @@ -258,11 +345,212 @@ export function classifyMethod( export function classifyInObservedClass( member: arkts.AstNode, classScopeInfo: ClassScopeInfo -): ObservedTranslator | MethodTranslator | undefined { +): BaseObservedPropertyTranslator | BaseMethodTranslator | undefined { if (arkts.isClassProperty(member)) { return classifyObservedClassProperty(member, classScopeInfo); } else if (arkts.isMethodDefinition(member)) { - return classifyMethod(member, false, classScopeInfo.className); + return classifyMethod(member, { isFromStruct: false, className: classScopeInfo.className }); + } + return undefined; +} + +export function classifyPropertyFromInfo( + node: arkts.ClassProperty, + metadata: StructPropertyInfo +): PropertyCachedTranslator | undefined { + if (!metadata.structInfo || !!metadata.structInfo.isDecl) { + return undefined; + } + if (StaticPropertyCachedTranslator.canBeStaticTranslate(node, metadata)) { + return new StaticPropertyCachedTranslator({ property: node, propertyInfo: metadata }); + } + const annotationInfo = metadata.annotationInfo; + if (!annotationInfo) { + return new RegularPropertyCachedTranslator({ property: node, propertyInfo: metadata }); + } + let propertyTranslator: PropertyCachedTranslator | undefined; + propertyTranslator = classifyV1PropertyFromInfo(node, metadata); + if (!!propertyTranslator) { + return propertyTranslator; + } + propertyTranslator = classifyV2PropertyFromInfo(node, metadata); + if (!!propertyTranslator) { + return propertyTranslator; + } + return undefined; +} + +export function classifyV1PropertyFromInfo( + node: arkts.ClassProperty, + metadata: StructPropertyInfo +): PropertyCachedTranslator | undefined { + const property: arkts.ClassProperty = node; + const propertyInfo: StructPropertyInfo = metadata; + const annotationInfo: StructPropertyAnnotationInfo = metadata.annotationInfo!; + if (annotationInfo.hasState) { + return new StateCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasStorageLink) { + return new StorageLinkCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasLocalStorageLink) { + return new LocalStorageLinkCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasLink) { + return new LinkCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasObjectLink) { + return new ObjectLinkCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasLocalStoragePropRef) { + return new LocalStoragePropRefCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasStoragePropRef) { + return new StoragePropRefCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasPropRef) { + return new PropRefCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasProvide) { + return new ProvideCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasConsume) { + return new ConsumeCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasBuilderParam) { + return new BuilderParamCachedTranslator({ property, propertyInfo }); + } + return undefined; +} + +export function classifyV2PropertyFromInfo( + node: arkts.ClassProperty, + metadata: StructPropertyInfo +): PropertyCachedTranslator | undefined { + const property: arkts.ClassProperty = node; + const propertyInfo: StructPropertyInfo = metadata; + const annotationInfo: StructPropertyAnnotationInfo = metadata.annotationInfo!; + if (annotationInfo.hasLocal) { + return new LocalCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasOnce) { + return new OnceCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasParam) { + return new ParamCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasProvider) { + return new ProviderCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasConsumer) { + return new ConsumerCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasEvent) { + return new EventCachedTranslator({ property, propertyInfo }); + } + if (annotationInfo.hasRequire) { + return new RequireCachedTranslator({ property, propertyInfo }); + } + return undefined; +} + +export function classifyPropertyInInterfaceFromInfo( + property: T, + metadata?: CustomComponentInterfacePropertyInfo +): InterfacePropertyCachedTranslator | undefined { + const propertyInfo = metadata; + let interfacePropertyTranslater: InterfacePropertyCachedTranslator | undefined; + interfacePropertyTranslater = classifyV1PropertyInInterfaceFromInfo(property, propertyInfo); + if (!!interfacePropertyTranslater) { + return interfacePropertyTranslater; + } + interfacePropertyTranslater = classifyV2PropertyInInterfaceFromInfo(property, propertyInfo); + if (!!interfacePropertyTranslater) { + return interfacePropertyTranslater; + } + if (RegularCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new RegularCachedInterfaceTranslator({ property, propertyInfo }); + } + return undefined; +} + +export function classifyV1PropertyInInterfaceFromInfo( + property: T, + metadata?: CustomComponentInterfacePropertyInfo +): InterfacePropertyCachedTranslator | undefined { + const propertyInfo = metadata; + if (StateCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new StateCachedInterfaceTranslator({ property, propertyInfo }); + } + if (LinkCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new LinkCachedInterfaceTranslator({ property, propertyInfo }); + } + if (PropRefCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new PropRefCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ProvideCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ProvideCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ConsumeCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ConsumeCachedInterfaceTranslator({ property, propertyInfo }); + } + if (StorageLinkCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new StorageLinkCachedInterfaceTranslator({ property, propertyInfo }); + } + if (StoragePropRefCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new StoragePropRefCachedInterfaceTranslator({ property, propertyInfo }); + } + if (LocalStoragePropRefCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new LocalStoragePropRefCachedInterfaceTranslator({ property, propertyInfo }); + } + if (BuilderParamCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new BuilderParamCachedInterfaceTranslator({ property, propertyInfo }); + } + if (LocalStorageLinkCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new LocalStorageLinkCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ObjectLinkCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ObjectLinkCachedInterfaceTranslator({ property, propertyInfo }); + } + return undefined; +} + +export function classifyV2PropertyInInterfaceFromInfo( + property: T, + metadata?: CustomComponentInterfacePropertyInfo +): InterfacePropertyCachedTranslator | undefined { + const propertyInfo = metadata; + if (LocalCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new LocalCachedInterfaceTranslator({ property, propertyInfo }); + } + if (OnceCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new OnceCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ParamCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ParamCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ProviderCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ProviderCachedInterfaceTranslator({ property, propertyInfo }); + } + if (ConsumerCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new ConsumerCachedInterfaceTranslator({ property, propertyInfo }); + } + if (EventCachedInterfaceTranslator.canBeTranslated(property, propertyInfo)) { + return new EventCachedInterfaceTranslator({ property, propertyInfo }); + } + return undefined; +} + +export function classifyObservedClassPropertyFromInfo( + property: arkts.ClassProperty, + propertyInfo: NormalClassPropertyInfo +): BaseObservedPropertyTranslator | undefined { + const classAnnotationInfo: NormalClassAnnotationInfo | undefined = propertyInfo.classInfo?.annotationInfo; + if (classAnnotationInfo?.hasObservedV2) { + return new ObservedV2TraceCachedTranslator({ property, propertyInfo }); + } + if (classAnnotationInfo?.hasObserved || propertyInfo.annotationInfo?.hasTrack) { + return new ObservedTrackCachedTranslator({ property, propertyInfo }); } return undefined; } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/link.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/link.ts index 75b65dc03c53cdf14aa234e45371bb0aad3dcb73..fb4ea2911183d104a700bf65cdee154c1d838dca 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/link.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/link.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { CustomComponentNames, optionsHasField } from '../utils'; import { generateToRecord, @@ -27,148 +27,142 @@ import { collectStateManagementTypeImport, hasDecorator, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export class LinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithLinkProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const test = factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + optionsHasField(originalName) + ); + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + arkts.factory.createTSNonNullExpression( + factory.createNonNullOrOptionalMemberExpression( + CustomComponentNames.COMPONENT_INITIALIZERS_NAME, + newName, + false, + true + ) + ), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); } + collectStateManagementTypeImport(this.stateManagementType); + collectStateManagementTypeImport(StateManagementTypes.LINK_SOURCE_TYPE); + const consequent = arkts.BlockStatement.createBlockStatement([ + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName, false, false), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ), + ]); + return arkts.factory.createIfStatement(test, consequent); +} - generateInitializeStruct(newName: string, originalName: string) { - const test = factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), - optionsHasField(originalName) - ); - - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - arkts.factory.createTSNonNullExpression( - factory.createNonNullOrOptionalMemberExpression( - CustomComponentNames.COMPONENT_INITIALIZERS_NAME, - newName, - false, - true - ) - ), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.LINK_DECORATED); - collectStateManagementTypeImport(StateManagementTypes.LINK_SOURCE_TYPE); - const consequent = arkts.BlockStatement.createBlockStatement([ - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName, false, false), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_LINK, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - ) - ), - ]); +export class LinkTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - return arkts.factory.createIfStatement(test, consequent); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.LINK_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - arkts.MemoNodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - arkts.MemoNodeCache.getInstance().collect(getter, metadata); - arkts.MemoNodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLinkProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); +export class LinkCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLinkProperty.bind(this)(newName, originalName, metadata); } } export class LinkInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.LINK; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LINK); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `DecoratedV1VariableBase | undefined`. - * - * @param method expecting getter with `@Link` and a setter with `@Link` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LINK, metadata); - } +export class LinkCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.LINK; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `DecoratedV1VariableBase | undefined`. - * - * @param property expecting property with `@Link`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LINK); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasLink; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/local.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/local.ts index 903044b0ac343a239faa09da80d3c544c792886d..33cdf20f7266712b4219d073c10d80f207ad5cda 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/local.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/local.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { createGetter, createSetter2, @@ -25,158 +25,283 @@ import { hasDecorator, collectStateManagementTypeImport, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, InterfacePropertyTranslator, InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, PropertyTranslator, PropertyTranslatorOptions, } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; import { factory } from './factory'; import { factory as UIFactory } from '../ui-factory'; import { PropertyCache } from './cache/propertyCache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; -export class LocalTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - private isStatic: boolean; +function factoryCallWithLocalProperty( + this: BasePropertyTranslator, + originalName: string, + metadata?: AstNodeCacheValueMetadata, + isStatic?: boolean +): arkts.CallExpression | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; + } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + collectStateManagementTypeImport(this.stateManagementType); + const factoryCall: arkts.CallExpression = factory.generateStateMgmtFactoryCall( + this.makeType, + this.propertyType?.clone(), + args, + !isStatic, + metadata + ); + return factoryCall; +} + +function initializeStructWithLocalProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + const factoryCall = factoryCallWithLocalProperty.bind(this)(originalName, metadata); + if (!factoryCall) { + return undefined; + } + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factoryCall, + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} + +function fieldWithStaticLocalProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.ClassProperty | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; + } + const factoryCall = factoryCallWithLocalProperty.bind(this)(originalName, metadata, true); + if (!factoryCall) { + return undefined; + } + const field = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(newName), + factoryCall, + factory.createStageManagementType(this.stateManagementType, this.propertyType), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + false + ); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(field, metadata); + } + return field; +} + +function getterWithStaticLocalProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + structName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.MethodDefinition { + const thisValue: arkts.Expression = UIFactory.generateMemberExpression( + arkts.factory.createIdentifier(structName), + newName + ); + const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); + const getter: arkts.MethodDefinition = createGetter( + originalName, + this.propertyType, + thisGet, + this.isMemoCached, + true, + metadata + ); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(getter, metadata); + } + return getter; +} + +function setterWithStaticLocalProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + structName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.MethodDefinition { + const thisValue: arkts.Expression = UIFactory.generateMemberExpression( + arkts.factory.createIdentifier(structName), + newName + ); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + generateGetOrSetCall(thisValue, GetSetTypes.SET) + ); + const setter: arkts.MethodDefinition = createSetter2(originalName, this.propertyType, thisSet, true); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(setter, metadata); + } + return setter; +} + +export class LocalTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + protected isStatic?: boolean; constructor(options: PropertyTranslatorOptions) { super(options); this.isStatic = this.property.isStatic; + if (this.isStatic) { + this.hasInitializeStruct = false; + this.makeType = StateManagementTypes.MAKE_STATIC_LOCAL; + } } - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + if (this.isStatic && !!originalName) { + const property = fieldWithStaticLocalProperty.bind(this)(newName, originalName, metadata); + if (!!property) { + return property; + } + } + return super.field(newName, originalName, metadata); } - cacheTranslatedInitializer(newName: string, originalName: string): void { - if (!this.isStatic) { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + if (this.isStatic) { + return getterWithStaticLocalProperty.bind(this)(newName, originalName, this.structInfo.name, metadata); } + return super.getter(newName, originalName, metadata); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = this.createPropertyField(newName, originalName); - const thisValue: arkts.Expression = this.isStatic - ? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(this.structInfo.name), newName) - : generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - arkts.MemoNodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - arkts.MemoNodeCache.getInstance().collect(getter, metadata); - arkts.MemoNodeCache.getInstance().collect(setter, metadata); + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + if (this.isStatic) { + return setterWithStaticLocalProperty.bind(this)(newName, originalName, this.structInfo.name, metadata); } - return [field, getter, setter]; - } - - createPropertyField(newName: string, originalName: string): arkts.ClassProperty { - return this.isStatic - ? arkts.factory.createClassProperty( - arkts.factory.createIdentifier(newName), - this.generateInitializeValue(originalName), - factory.createStageManagementType(StateManagementTypes.LOCAL_DECORATED, this.propertyType), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, - false - ) - : factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.LOCAL_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - } - - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue, false, this.isStatic); + return super.setter(newName, originalName, metadata); } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement, this.isStatic); - } - - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - collectStateManagementTypeImport(StateManagementTypes.LOCAL_DECORATED); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - this.generateInitializeValue(originalName), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); - } - - generateInitializeValue(originalName: string): arkts.Expression { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; - collectStateManagementTypeImport(StateManagementTypes.LOCAL_DECORATED); - return factory.generateStateMgmtFactoryCall( - this.isStatic ? StateManagementTypes.MAKE_STATIC_LOCAL : StateManagementTypes.MAKE_LOCAL, - this.propertyType?.clone(), - args, - !this.isStatic, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + if (this.isStatic) { + return undefined; + } + return initializeStructWithLocalProperty.bind(this)(newName, originalName, metadata); } } -export class LocalInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; +export class LocalCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + protected isStatic?: boolean; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.isStatic = this.property.isStatic; + if (this.isStatic) { + this.hasInitializeStruct = false; + this.makeType = StateManagementTypes.MAKE_STATIC_LOCAL; } - return this.property; } - 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; + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + if (this.isStatic && !!originalName) { + const property = fieldWithStaticLocalProperty.bind(this)(newName, originalName, metadata); + if (!!property) { + return property; + } } - return false; + return super.field(newName, originalName, metadata); + } + + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + if (this.isStatic) { + const structName: string = this.propertyInfo.structInfo?.name!; + return getterWithStaticLocalProperty.bind(this)(newName, originalName, structName, metadata); + } + return super.getter(newName, originalName, metadata); + } + + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + if (this.isStatic) { + const structName: string = this.propertyInfo.structInfo?.name!; + return setterWithStaticLocalProperty.bind(this)(newName, originalName, structName, metadata); + } + return super.setter(newName, originalName, metadata); + } + + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + if (this.isStatic) { + return undefined; + } + return initializeStructWithLocalProperty.bind(this)(newName, originalName, metadata); } +} + +export class LocalInterfaceTranslator extends InterfacePropertyTranslator { + protected decorator: DecoratorNames = DecoratorNames.LOCAL; /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `ILocalDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Local` and a setter with `@Local` in the overloads. + * @deprecated */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL, metadata); + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.LOCAL); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL); + } + return false; } +} + +export class LocalCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.LOCAL; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `ILocalDecoratedVariable | undefined`. - * - * @param property expecting property with `@Local`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasLocal; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts index 07cb19c43a2f61a236f87764ee89837133d2f4b6..b1b497cd03fda010e527c833a3d787b0e5d027a9 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/localStoragePropRef.ts @@ -16,9 +16,17 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { generateToRecord, createGetter, @@ -29,141 +37,134 @@ import { hasDecorator, getValueInAnnotation, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; - -export class LocalStoragePropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithLocalStoragePropRefProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const localStoragePropRefValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.LOCAL_STORAGE_PROP_REF + ); + if (!localStoragePropRefValueStr) { + return undefined; } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(localStoragePropRefValueStr), + arkts.factory.createStringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); + } + collectStateManagementTypeImport(this.stateManagementType); + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const localStoragePropRefValueStr: string | undefined = getValueInAnnotation( - this.property, - DecoratorNames.LOCAL_STORAGE_PROP_REF - ); - if (!localStoragePropRefValueStr) { - throw new Error('LocalStoragePropRef required only one value!!'); - } +export class LocalStoragePropRefTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL_STORAGE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(localStoragePropRefValueStr), - arkts.factory.createStringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED); - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_LOCAL_STORAGE_PROP_REF, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLocalStoragePropRefProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); +export class LocalStoragePropRefCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_STORAGE_PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL_STORAGE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLocalStoragePropRefProperty.bind(this)(newName, originalName, metadata); } } export class LocalStoragePropRefInterfaceTranslator< - T extends InterfacePropertyTypes + T extends InterfacePropertyTypes, > extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.LOCAL_STORAGE_PROP_REF; + /** + * @deprecated + */ 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.id) && 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; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `ILocalStoragePropRefDecoratedVariable | undefined`. - * - * @param method expecting getter with `@LocalStoragePropRef` and a setter with `@LocalStoragePropRef` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL_STORAGE_PROP_REF, metadata); - } +export class LocalStoragePropRefCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.LOCAL_STORAGE_PROP_REF; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `ILocalStoragePropRefDecoratedVariable | undefined`. - * - * @param property expecting property with `@LocalStoragePropRef`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL_STORAGE_PROP_REF); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return ( + !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && + !!metadata.annotationInfo?.hasLocalStoragePropRef + ); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts index 19ba23f333f1e5902d945c91023fe80380b01cd8..aa45ea2ecf2f686b6bc5fa8470ff79ac7072e162 100755 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts @@ -16,9 +16,17 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { generateToRecord, createGetter, @@ -29,141 +37,129 @@ import { hasDecorator, getValueInAnnotation, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; - -export class LocalStorageLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithLocalStorageLinkProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const localStorageLinkValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.LOCAL_STORAGE_LINK + ); + if (!localStorageLinkValueStr) { + return undefined; } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(localStorageLinkValueStr), + arkts.factory.createStringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); + } + collectStateManagementTypeImport(this.stateManagementType); + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const localStorageLinkValueStr: string | undefined = getValueInAnnotation( - this.property, - DecoratorNames.LOCAL_STORAGE_LINK - ); - if (!localStorageLinkValueStr) { - throw new Error('LocalStorageLink required only one value!!'); - } +export class LocalStorageLinkTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL_STORAGE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(localStorageLinkValueStr), - arkts.factory.createStringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED); - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_LOCAL_STORAGE_LINK, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLocalStorageLinkProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); +export class LocalStorageLinkCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.LOCAL_STORAGE_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_LOCAL_STORAGE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithLocalStorageLinkProperty.bind(this)(newName, originalName, metadata); } } export class LocalStorageLinkInterfaceTranslator< - T extends InterfacePropertyTypes + T extends InterfacePropertyTypes, > extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.LOCAL_STORAGE_LINK; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_LINK); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `MutableState | undefined`. - * - * @param method expecting getter with `@LocalStorageLink` and a setter with `@LocalStorageLink` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL_STORAGE_LINK, metadata); - } +export class LocalStorageLinkCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.LOCAL_STORAGE_LINK; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `MutableState | undefined`. - * - * @param property expecting property with `@LocalStorageLink`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL_STORAGE_LINK); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return ( + !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasLocalStorageLink + ); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/monitor.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/monitor.ts index 43a6180dcdd2a5f74cd4072f8db81f41b13d408e..e3234c725da03cda92772ce815377c4ade743c12 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/monitor.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/monitor.ts @@ -17,14 +17,62 @@ import * as arkts from '@koalaui/libarkts'; import { expectName } from '../../common/arkts-utils'; import { StateManagementTypes } from '../../common/predefines'; +import { checkIsStructMethodFromInfo } from '../../collectors/ui-collectors/utils'; import { monitorField } from '../utils'; import { collectStateManagementTypeImport, getValueInMonitorAnnotation } from './utils'; -import { MethodTranslator } from './base'; -import { InitializerConstructor } from './types'; +import { BaseMethodTranslator, MethodCacheTranslator, MethodTranslator } from './base'; import { factory as UIFactory } from '../ui-factory'; import { MonitorCache, MonitorInfo } from './cache/monitorCache'; -export class MonitorTranslator extends MethodTranslator implements InitializerConstructor { +function fieldWithMonitorMethod( + this: BaseMethodTranslator, + newName: string, + originalName?: string +): arkts.ClassProperty { + collectStateManagementTypeImport(StateManagementTypes.MONITOR_DECORATED); + const field: arkts.ClassProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(newName), + undefined, + arkts.factory.createETSUnionType([ + UIFactory.createTypeReferenceFromString(StateManagementTypes.MONITOR_DECORATED), + arkts.factory.createETSUndefinedType(), + ]), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, + false + ); + return field; +} + +function monitorInfo( + this: BaseMethodTranslator, + newName: string, + originalName: string, + isFromStruct: boolean +): MonitorInfo { + const monitorItem: string[] | undefined = getValueInMonitorAnnotation(this.method.function.annotations); + const monitorInfo: MonitorInfo = { + monitorItem: monitorItem, + originalName: originalName, + newName: newName, + isFromStruct, + }; + return monitorInfo; +} + +export interface IMonitorTranslator { + field(newName: string, originalName?: string): arkts.ClassProperty; + monitorInfo(newName: string, originalName: string): MonitorInfo; +} + +export class MonitorTranslator extends MethodTranslator implements IMonitorTranslator { + field(newName: string, originalName?: string): arkts.ClassProperty { + return fieldWithMonitorMethod.bind(this)(newName, originalName); + } + + monitorInfo(newName: string, originalName: string): MonitorInfo { + return monitorInfo.bind(this)(newName, originalName, this.classInfo.isFromStruct); + } + translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.method.id); const newName: string = monitorField(originalName); @@ -33,32 +81,48 @@ export class MonitorTranslator extends MethodTranslator implements InitializerCo } cacheTranslatedInitializer(newName: string, originalName: string): void { - const monitorItem: string[] | undefined = getValueInMonitorAnnotation( - this.method.function!.annotations - ); - const monitorPathsStr: string = !!monitorItem ? monitorItem.join(',') : ''; - const monitorInfo: MonitorInfo = { - monitorItem: monitorItem, - originalName: originalName, - newName: newName, - isFromStruct: this.classInfo.isFromStruct - }; - MonitorCache.getInstance().collectMonitors(this.classInfo.className, monitorPathsStr, monitorInfo); + const info: MonitorInfo = this.monitorInfo(newName, originalName); + const monitorPathsStr: string = !!info.monitorItem ? info.monitorItem.join(',') : ''; + MonitorCache.getInstance().collectMonitors(this.classInfo.className, monitorPathsStr, info); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - collectStateManagementTypeImport(StateManagementTypes.MONITOR_DECORATED); - const field: arkts.ClassProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(newName), - undefined, - arkts.factory.createETSUnionType([ - UIFactory.createTypeReferenceFromString(StateManagementTypes.MONITOR_DECORATED), - arkts.factory.createETSUndefinedType(), - ]), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); - + const field = this.field(newName, originalName); return [field]; } } + +export class MonitorCacheTranslator extends MethodCacheTranslator implements IMonitorTranslator { + field(newName: string, originalName?: string): arkts.ClassProperty { + return fieldWithMonitorMethod.bind(this)(newName, originalName); + } + + monitorInfo(newName: string, originalName: string): MonitorInfo { + const isFromStruct = checkIsStructMethodFromInfo(this.methodInfo); + return monitorInfo.bind(this)(newName, originalName, isFromStruct); + } + + translateMember(): arkts.AstNode[] { + const originalName: string = this.methodInfo.name!; + const newName: string = monitorField(originalName); + this.cacheTranslatedInitializer(newName, originalName); + return this.translateWithoutInitializer(newName, originalName); + } + + cacheTranslatedInitializer(newName: string, originalName: string): void { + const info: MonitorInfo = this.monitorInfo(newName, originalName); + const monitorPathsStr: string = !!info.monitorItem ? info.monitorItem.join(',') : ''; + let className: string; + if (checkIsStructMethodFromInfo(this.methodInfo)) { + className = this.methodInfo.structInfo?.name!; + } else { + className = this.methodInfo.classInfo?.name!; + } + MonitorCache.getInstance().collectMonitors(className, monitorPathsStr, info); + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = this.field(newName, originalName); + return [field, this.method]; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/objectlink.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/objectlink.ts index 56d0ebb031249ee25202596ad521217aa0674d59..e9b0bbbdbbc8fc3de1def494a557d2e9973f35e6 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/objectlink.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/objectlink.ts @@ -16,152 +16,140 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { CustomComponentNames } from '../utils'; -import { createGetter, findCachedMemoMetadata, generateGetOrSetCall, generateThisBacking, generateToRecord, hasDecorator } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + checkIsNameStartWithBackingField, + createGetter, + findCachedMemoMetadata, + generateGetOrSetCall, + generateThisBacking, + generateToRecord, + hasDecorator, +} from './utils'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata } from '../../common/node-cache'; -export class ObjectLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithObjectLinkProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - const updateStruct: arkts.AstNode = this.generateUpdateStruct(newName, originalName); - PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const initializers = arkts.factory.createTSAsExpression( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + originalName + ), + this.propertyType, + false + ); + const args: arkts.Expression[] = [arkts.factory.createStringLiteral(originalName), initializers]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); } + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const initializers = arkts.factory.createTSAsExpression( - factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), - originalName - ), - this.propertyType, - false - ); - const args: arkts.Expression[] = [arkts.factory.createStringLiteral(originalName), initializers]; - factory.judgeIfAddWatchFunc(args, this.property); +export class ObjectLinkTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.OBJECT_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_OBJECT_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = false; - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_OBJECT_LINK, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - generateUpdateStruct(newName: string, originalName: string): arkts.AstNode { - const member: arkts.MemberExpression = arkts.factory.createMemberExpression( - generateThisBacking(newName, false, true), - arkts.factory.createIdentifier(StateManagementTypes.UPDATE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); - const nonNullItem = arkts.factory.createTSAsExpression( - factory.createNonNullOrOptionalMemberExpression( - CustomComponentNames.COMPONENT_INITIALIZERS_NAME, - originalName, - false, - true - ), - this.propertyType, - false - ); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(nonNullItem, { ...metadata, isWithinTypeParams: true }); - } - return factory.createIfInUpdateStruct(originalName, member, [nonNullItem]); + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithObjectLinkProperty.bind(this)(newName, originalName, metadata); } +} - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.OBJECT_LINK_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - } - return [field, getter]; +export class ObjectLinkCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.OBJECT_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_OBJECT_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = false; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateGetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithObjectLinkProperty.bind(this)(newName, originalName, metadata); } } export class ObjectLinkInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.OBJECT_LINK; + /** + * @deprecated + */ static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.OBJECT_LINK)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.OBJECT_LINK)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.OBJECT_LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.OBJECT_LINK); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `ObjectLinkDecoratedVariable | undefined`. - * - * @param method expecting getter with `@ObjectLink` and a setter with `@ObjectLink` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.OBJECT_LINK, metadata); - } +export class ObjectLinkCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.OBJECT_LINK; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `ObjectLinkDecoratedVariable | undefined`. - * - * @param property expecting property with `@ObjectLink`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.OBJECT_LINK); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasObjectLink; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/observedTrack.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/observedTrack.ts index 764874fdaab9bf50048441a75863f1242c3b1091..a54946f185e4b96ece1bcdc69a3daef9f580effc 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/observedTrack.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/observedTrack.ts @@ -16,7 +16,13 @@ import * as arkts from '@koalaui/libarkts'; import { annotation, backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, StateManagementTypes, ObservedNames } from '../../common/predefines'; -import { ObservedPropertyTranslator } from './base'; +import { + IBaseObservedPropertyTranslator, + ObservedPropertyCachedTranslator, + ObservedPropertyCachedTranslatorOptions, + ObservedPropertyTranslator, + ObservedPropertyTranslatorOptions, +} from './base'; import { collectStateManagementTypeImport, generateThisBacking, @@ -31,235 +37,230 @@ import { factory as uiFactory } from '../ui-factory'; import { logDiagnostic } from '../interop/initstatevar'; import { getHasAnnotationObserved } from '../interop/interop'; -export class ObservedTrackTranslator extends ObservedPropertyTranslator { - private hasImplement: boolean; - private isTracked: boolean; +export function getterBodyWithObservedTrackProperty( + this: IObservedTrackTranslator, + originalName: string, + newName: string +): arkts.BlockStatement { + const conditionalAddRef = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression(generateThisBacking(ObservedNames.CONDITIONAL_ADD_REF), [ + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + metaIdentifier.bind(this)(originalName), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + ], + undefined, + false, + false + ) + ); + const backingMember: arkts.Expression = generateThisBacking(newName); + const returnMember: arkts.ReturnStatement = arkts.factory.createReturnStatement( + !this.property || this.property.value + ? backingMember + : arkts.factory.createTSAsExpression(backingMember, this.propertyType, false) + ); + return arkts.factory.createBlockStatement([conditionalAddRef, returnMember]); +} - constructor(property: arkts.ClassProperty, classScopeInfo: ClassScopeInfo) { - super(property, classScopeInfo); - this.hasImplement = expectName(this.property.key).startsWith(ObservedNames.PROPERTY_PREFIX); - this.isTracked = hasDecorator(this.property, DecoratorNames.TRACK); - this.checkObservedV2WhenInterop(property); - } +function getterWithObservedTrackProperty( + this: IObservedTrackTranslator, + originalName: string, + newName: string +): arkts.MethodDefinition { + const body = getterBodyWithObservedTrackProperty.bind(this)(originalName, newName); + return uiFactory.createMethodDefinition({ + kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, + key: arkts.factory.createIdentifier(originalName), + function: { + body: body, + returnTypeAnnotation: this.propertyType, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_GETTER, + }, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + }); +} - checkObservedV2WhenInterop(property: arkts.ClassProperty): void { - const isObservedFrom1_1 = getHasAnnotationObserved(property, 'ObservedV2'); - if (isObservedFrom1_1) { - const errorMessage = `The type of the regular property can not be a class decorated with @ObservedV2 when interop`; - logDiagnostic(errorMessage, property); - } - } +function setterWithObservedTrackProperty( + this: IObservedTrackTranslator, + originalName: string, + newName: string +): arkts.MethodDefinition { + const ifEqualsNewValue: arkts.IfStatement = setterIfEqualsNewValueWithObservedTrackProperty.bind(this)( + originalName, + newName + ); + const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); + const param = arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, this.propertyType), + false, + undefined + ); - translateMember(): arkts.AstNode[] { - if (!this.isTracked && (this.classScopeInfo.classHasTrack || !this.classScopeInfo.isObserved)) { - return [this.property]; - } - const originalName: string = this.hasImplement - ? removeImplementProperty(expectName(this.property.key)) - : expectName(this.property.key); - const newName: string = backingField(originalName); - const field = this.createField(originalName, newName); - this.transformGetterSetter(originalName, newName); - return [...field]; - } + return uiFactory.createMethodDefinition({ + kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET, + key: arkts.factory.createIdentifier(originalName), + function: { + body: body, + params: [param], + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER, + }, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + }); +} - createField(originalName: string, newName: string): arkts.ClassProperty[] { - const backingField = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(newName), - this.property.value, - this.propertyType, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); - if (!this.property.value) { - backingField.modifiers |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; - } - const annotations: arkts.AnnotationUsage[] = [...this.property.annotations]; - if ( - !hasDecoratorName(this.property, DecoratorNames.JSONSTRINGIFYIGNORE) && - !hasDecoratorName(this.property, DecoratorNames.JSONRENAME) - ) { - annotations.push( - annotation(DecoratorNames.JSONRENAME).addProperty( - arkts.factory.createClassProperty( - arkts.factory.createIdentifier(ObservedNames.NEW_NAME), - arkts.factory.createStringLiteral(originalName), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false - ) - ) - ); - } - backingField.setAnnotations(annotations); - removeDecorator(backingField, DecoratorNames.TRACK); - if (!this.isTracked) { - return [backingField]; - } - const metaField = this.metaField(originalName); - metaField.setAnnotations([annotation(DecoratorNames.JSONSTRINGIFYIGNORE), annotation(DecoratorNames.JSONPARSEIGNORE)]); - return [backingField, metaField]; - } +export function metaIdentifier(this: IObservedTrackTranslator, originalName: string): arkts.Identifier { + return this.isTracked + ? arkts.factory.createIdentifier(`${StateManagementTypes.META}_${originalName}`) + : arkts.factory.createIdentifier(StateManagementTypes.META); +} - createGetter(originalName: string, newName: string): arkts.MethodDefinition { - const conditionalAddRef = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(generateThisBacking(ObservedNames.CONDITIONAL_ADD_REF), [ +export function setterIfEqualsNewValueWithObservedTrackProperty( + this: IObservedTrackTranslator, + originalName: string, + newName: string +): arkts.IfStatement { + const backingValue = generateThisBacking(newName); + const setNewValue = arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + backingValue, + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); + const fireChange = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( arkts.factory.createMemberExpression( arkts.factory.createThisExpression(), - this.metaIdentifier(originalName), + metaIdentifier.bind(this)(originalName), arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, false, false ), - ], undefined, false, false) - ); - const backingMember: arkts.Expression = generateThisBacking(newName); - const returnMember: arkts.ReturnStatement = arkts.factory.createReturnStatement( - this.property.value - ? backingMember - : arkts.factory.createTSAsExpression(backingMember, this.propertyType, false) - ); - const body = arkts.factory.createBlockStatement([conditionalAddRef, returnMember]); - return uiFactory.createMethodDefinition({ - kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, - key: arkts.factory.createIdentifier(originalName), - function: { - body: body, - returnTypeAnnotation: this.propertyType, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_GETTER, - }, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - }); - } - - createSetter(originalName: string, newName: string): arkts.MethodDefinition { - const ifEqualsNewValue: arkts.IfStatement = this.setterIfEqualsNewValue(originalName, newName); - const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); - const param = arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, this.propertyType), + arkts.factory.createIdentifier(ObservedNames.FIRE_CHANGE), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [], + undefined, false, - undefined - ); + false + ) + ); + const subscribingWatches = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression(generateThisBacking(ObservedNames.EXECUATE_WATCHES), [ + arkts.factory.createStringLiteral(originalName), + ], + undefined, + false, + false + ) + ); + return arkts.factory.createIfStatement( + arkts.factory.createBinaryExpression( + backingValue, + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL + ), + arkts.factory.createBlockStatement([setNewValue, fireChange, subscribingWatches]) + ); +} - return uiFactory.createMethodDefinition({ - kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET, - key: arkts.factory.createIdentifier(originalName), - function: { - body: body, - params: [param], - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER, - }, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - }); +function checkObservedV2WhenInterop(property: arkts.ClassProperty): void { + const isObservedFrom1_1 = getHasAnnotationObserved(property, 'ObservedV2'); + if (isObservedFrom1_1) { + const errorMessage = `The type of the regular property can not be a class decorated with @ObservedV2 when interop`; + logDiagnostic(errorMessage, property); } +} - metaIdentifier(originalName: string): arkts.Identifier { - return this.isTracked - ? arkts.factory.createIdentifier(`${StateManagementTypes.META}_${originalName}`) - : arkts.factory.createIdentifier(StateManagementTypes.META); - } +export interface IObservedTrackTranslator extends IBaseObservedPropertyTranslator { + traceDecorator: DecoratorNames.TRACK; + isTracked?: boolean; + isStatic?: boolean; +} - transformGetterSetter(originalName: string, newName: string): void { - const newGetter = this.createGetter(originalName, newName); - const newSetter = this.createSetter(originalName, newName); - if (this.hasImplement) { - { - const idx: number = this.classScopeInfo.getters.findIndex( - (getter) => getter.id?.name === originalName - ); - const originGetter: arkts.MethodDefinition = this.classScopeInfo.getters[idx]; - const originSetter: arkts.MethodDefinition = originGetter.overloads[0]; +export class ObservedTrackTranslator extends ObservedPropertyTranslator implements IObservedTrackTranslator { + traceDecorator: DecoratorNames.TRACK = DecoratorNames.TRACK; + isTracked?: boolean; + isStatic: boolean = false; // @Observed does not support static property. + propertyModifier: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + protected hasBackingField: boolean = true; + protected hasMetaField: boolean = false; + protected hasGetterSetter: boolean = true; - const updatedSetter = arkts.factory.updateMethodDefinition( - originSetter, - originSetter.kind, - newSetter.id?.clone(), - arkts.factory.createFunctionExpression(newSetter.id?.clone(), newSetter.function! - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_OVERLOAD) - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD) - ), - originSetter.modifiers, - false, - originSetter.overloads - ); + constructor(options: ObservedPropertyTranslatorOptions) { + super(options); + this.isTracked = hasDecorator(this.property, this.traceDecorator); + this.hasMetaField = this.isTracked; // meta field is generated only if property is @Track + checkObservedV2WhenInterop(this.property); + } - const updateGetter: arkts.MethodDefinition = arkts.factory.updateMethodDefinition( - originGetter, - originGetter.kind, - newGetter.id?.clone(), - arkts.factory.createFunctionExpression(newGetter.id?.clone(), newGetter.function! - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD) - ), - originGetter.modifiers, - false, - [updatedSetter] - ); - this.classScopeInfo.getters[idx] = updateGetter; - } - } else { - this.classScopeInfo.getters.push(...[newGetter, newSetter]); + translateMember(): arkts.AstNode[] { + if (!this.isTracked && (this.classScopeInfo.classHasTrack || !this.classScopeInfo.isObserved)) { + return [this.property]; } + return super.translateMember(); } - metaField(originalName: string): arkts.ClassProperty { - collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META); - return arkts.factory.createClassProperty( - arkts.factory.createIdentifier(`${StateManagementTypes.META}_${originalName}`), - factory.generateStateMgmtFactoryCall(StateManagementTypes.MAKE_MUTABLESTATE_META, undefined, [], false), - uiFactory.createTypeReferenceFromString(StateManagementTypes.MUTABLE_STATE_META), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); + metaField(originalName: string, newName: string): arkts.ClassProperty { + const field = super.metaField.bind(this)(originalName, newName); + field.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); + return field; } - setterIfEqualsNewValue(originalName: string, newName: string): arkts.IfStatement { - const backingValue = generateThisBacking(newName); + getter(originalName: string, newName: string): arkts.MethodDefinition { + return getterWithObservedTrackProperty.bind(this)(originalName, newName); + } - const setNewValue = arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - backingValue, - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + setter(originalName: string, newName: string): arkts.MethodDefinition { + return setterWithObservedTrackProperty.bind(this)(originalName, newName); + } +} - const fireChange = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - this.metaIdentifier(originalName), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - arkts.factory.createIdentifier(ObservedNames.FIRE_CHANGE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - [], - undefined, - false, - false - ) - ); +export class ObservedTrackCachedTranslator + extends ObservedPropertyCachedTranslator + implements IObservedTrackTranslator +{ + traceDecorator: DecoratorNames.TRACK = DecoratorNames.TRACK; + isTracked?: boolean; + isStatic: boolean = false; // @Observed does not support static property. + propertyModifier: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + protected hasBackingField: boolean = true; + protected hasMetaField: boolean = false; + protected hasGetterSetter: boolean = true; - const subscribingWatches = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(generateThisBacking(ObservedNames.EXECUATE_WATCHES), [ - arkts.factory.createStringLiteral(originalName), - ], undefined, false, false) - ); + constructor(options: ObservedPropertyCachedTranslatorOptions) { + super(options); + this.isTracked = !!this.propertyInfo.annotationInfo?.hasTrack; + this.hasMetaField = this.isTracked; // meta field is generated only if property is @Track + checkObservedV2WhenInterop(this.property); + } - return arkts.factory.createIfStatement( - arkts.factory.createBinaryExpression( - backingValue, - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL - ), - arkts.factory.createBlockStatement([setNewValue, fireChange, subscribingWatches]) - ); + metaField(originalName: string, newName: string): arkts.ClassProperty { + const field = super.metaField.bind(this)(originalName, newName); + field.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); + return field; + } + + getter(originalName: string, newName: string): arkts.MethodDefinition { + return getterWithObservedTrackProperty.bind(this)(originalName, newName); + } + + setter(originalName: string, newName: string): arkts.MethodDefinition { + return setterWithObservedTrackProperty.bind(this)(originalName, newName); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/observedV2Trace.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/observedV2Trace.ts index 628c796a0fd6381a847336e01c4baefddb8aa0ce..56edd1b0e20497f812c60c4d47faff543a424848 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/observedV2Trace.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/observedV2Trace.ts @@ -16,7 +16,14 @@ import * as arkts from '@koalaui/libarkts'; import { annotation, backingField, expectName } from '../../common/arkts-utils'; import { DecoratorNames, ObservedNames, StateManagementTypes } from '../../common/predefines'; -import { ObservedPropertyTranslator } from './base'; +import { + BaseObservedPropertyTranslator, + IBaseObservedPropertyTranslator, + ObservedPropertyCachedTranslator, + ObservedPropertyCachedTranslatorOptions, + ObservedPropertyTranslator, + ObservedPropertyTranslatorOptions, +} from './base'; import { collectStateManagementTypeImport, generateThisBacking, @@ -32,268 +39,282 @@ import { ImportCollector } from '../../common/import-collector'; import { logDiagnostic } from '../interop/initstatevar'; import { getHasAnnotationObserved } from '../interop/interop'; -export class ObservedV2TraceTranslator extends ObservedPropertyTranslator { - private hasImplement: boolean; - private isTraced: boolean; - private isStatic: boolean; +export function getterBodyWithObservedV2TraceProperty( + this: IObservedV2TraceTranslator, + originalName: string, + newName: string +): arkts.BlockStatement { + const classIdent: arkts.Identifier = arkts.factory.createIdentifier(this.className); + ImportCollector.getInstance().collectImport(StateManagementTypes.UI_UTILS); + const observedMember: arkts.Expression = this.isStatic + ? uiFactory.generateMemberExpression(classIdent.clone(), newName) + : generateThisBacking(newName); + const returnMember: arkts.ReturnStatement = arkts.factory.createReturnStatement( + arkts.factory.createCallExpression( + uiFactory.generateMemberExpression( + arkts.factory.createIdentifier(StateManagementTypes.UI_UTILS), + StateManagementTypes.MAKE_OBSERVED + ), + [ + !this.property || this.property.value + ? observedMember + : arkts.factory.createTSAsExpression(observedMember, this.propertyType, false), + ], + undefined, + false, + false + ) + ); + return arkts.factory.createBlockStatement([createAddRef.bind(this)(originalName, classIdent), returnMember]); +} - constructor(property: arkts.ClassProperty, classScopeInfo: ClassScopeInfo) { - super(property, classScopeInfo); - this.hasImplement = expectName(this.property.key).startsWith(ObservedNames.PROPERTY_PREFIX); - this.isTraced = hasDecorator(this.property, DecoratorNames.TRACE); - this.checkObservedWhenInterop(property); - this.isStatic = arkts.hasModifierFlag(this.property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC); +function getterWithObservedV2TraceProperty( + this: IObservedV2TraceTranslator, + originalName: string, + newName: string +): arkts.MethodDefinition { + const methodModifier = this.isStatic + ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC + : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; + const body = getterBodyWithObservedV2TraceProperty.bind(this)(originalName, newName); + return uiFactory.createMethodDefinition({ + kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, + key: arkts.factory.createIdentifier(originalName), + function: { + body: body, + returnTypeAnnotation: this.propertyType, + modifiers: methodModifier, + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_GETTER, + }, + modifiers: methodModifier, + }); +} + +function setterWithObservedV2TraceProperty( + this: IObservedV2TraceTranslator, + originalName: string, + newName: string +): arkts.MethodDefinition { + const methodModifier = this.isStatic + ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC + : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; + const ifEqualsNewValue: arkts.IfStatement = setterIfEqualsNewValueWithObservedV2TraceProperty.bind(this)( + originalName, + newName + ); + const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); + const param = arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, this.propertyType), + false, + undefined + ); + return uiFactory.createMethodDefinition({ + kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET, + key: arkts.factory.createIdentifier(originalName), + function: { + body: body, + params: [param], + modifiers: methodModifier, + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER, + }, + modifiers: methodModifier, + }); +} + +function createAddRef( + this: IObservedV2TraceTranslator, + originalName: string, + classIdent: arkts.Identifier +): arkts.ExpressionStatement { + const metaName: string = `${StateManagementTypes.META}_${originalName}`; + const conditionalAddRef = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression(generateThisBacking(ObservedNames.CONDITIONAL_ADD_REF), [ + generateThisBacking(metaName), + ], + undefined, + false, + false + ) + ); + const metaAddRef = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + uiFactory.generateMemberExpression( + uiFactory.generateMemberExpression(classIdent.clone(), metaName), + ObservedNames.ADD_REF + ), + [], + undefined, + false, + false + ) + ); + return this.isStatic ? metaAddRef : conditionalAddRef; +} + +export function setterIfEqualsNewValueWithObservedV2TraceProperty( + this: IObservedV2TraceTranslator, + originalName: string, + newName: string +): arkts.IfStatement { + const classIdent: arkts.Identifier = arkts.factory.createIdentifier(this.className); + const metaName: string = `${StateManagementTypes.META}_${originalName}`; + const backingValue: arkts.Expression = generateThisBacking(newName); + const metaValue: arkts.Expression = generateThisBacking(metaName); + const staticMetaValue: arkts.Expression = uiFactory.generateMemberExpression(classIdent.clone(), metaName); + const staticBackingValue: arkts.Expression = uiFactory.generateMemberExpression(classIdent.clone(), newName); + const setNewValue = arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + this.isStatic ? staticBackingValue : backingValue, + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); + + const fireChange = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + this.isStatic ? staticMetaValue.clone() : metaValue.clone(), + arkts.factory.createIdentifier(ObservedNames.FIRE_CHANGE), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [], + undefined, + false, + false + ) + ); + + const subscribingWatches = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression(generateThisBacking(ObservedNames.EXECUATE_WATCHES), [ + arkts.factory.createStringLiteral(originalName), + ], + undefined, + false, + false + ) + ); + + const consequentArr = this.isStatic ? [setNewValue, fireChange] : [setNewValue, fireChange, subscribingWatches]; + return arkts.factory.createIfStatement( + arkts.factory.createBinaryExpression( + this.isStatic ? staticBackingValue.clone() : backingValue.clone(), + arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL + ), + arkts.factory.createBlockStatement(consequentArr) + ); +} + +function checkObservedWhenInterop(property: arkts.ClassProperty): void { + const isObservedFrom1_1 = getHasAnnotationObserved(property, 'Observed'); + if (isObservedFrom1_1) { + const errorMessage = `The type of the regular property can not be a class decorated with @Observed when interop`; + logDiagnostic(errorMessage, property); } +} + +export interface IObservedV2TraceTranslator extends IBaseObservedPropertyTranslator { + className: string; + traceDecorator: DecoratorNames.TRACE; + isTraced?: boolean; + isStatic?: boolean; +} - checkObservedWhenInterop(property: arkts.ClassProperty): void { - const isObservedFrom1_1 = getHasAnnotationObserved(property, 'Observed'); - if (isObservedFrom1_1) { - const errorMessage = `The type of the regular property can not be a class decorated with @Observed when interop`; - logDiagnostic(errorMessage, property); +export class ObservedV2TraceTranslator extends ObservedPropertyTranslator implements IObservedV2TraceTranslator { + traceDecorator: DecoratorNames.TRACE = DecoratorNames.TRACE; + className: string; + isTraced?: boolean; + isStatic?: boolean; + propertyModifier: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + protected hasBackingField: boolean = true; + protected hasMetaField: boolean = true; + protected hasGetterSetter: boolean = true; + + constructor(options: ObservedPropertyTranslatorOptions) { + super(options); + this.className = this.classScopeInfo.className; + this.hasImplement = expectName(this.property.key).startsWith(ObservedNames.PROPERTY_PREFIX); + this.isTraced = hasDecorator(this.property, this.traceDecorator); + this.isStatic = arkts.hasModifierFlag(this.property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC); + if (this.isStatic) { + this.propertyModifier = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC; } + checkObservedWhenInterop(this.property); } translateMember(): arkts.AstNode[] { if (!this.isTraced) { return [this.property]; } - const originalName: string = this.hasImplement - ? removeImplementProperty(expectName(this.property.key)) - : expectName(this.property.key); - const newName: string = backingField(originalName); - const field = this.createField(originalName, newName); - this.transformGetterSetter(originalName, newName); - return [...field]; + return super.translateMember(); } - createField(originalName: string, newName: string): arkts.ClassProperty[] { - const backingField = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(newName), - this.property.value, - this.propertyType, - this.isStatic - ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC - : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); - if (!this.property.value) { - backingField.modifiers |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL; - } - const annotations: arkts.AnnotationUsage[] = [...this.property.annotations]; - if ( - !hasDecoratorName(this.property, DecoratorNames.JSONSTRINGIFYIGNORE) && - !hasDecoratorName(this.property, DecoratorNames.JSONRENAME) - ) { - annotations.push( - annotation(DecoratorNames.JSONRENAME).addProperty( - arkts.factory.createClassProperty( - arkts.factory.createIdentifier(ObservedNames.NEW_NAME), - arkts.factory.createStringLiteral(originalName), - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - false - ) - ) - ); - } - backingField.setAnnotations(annotations); - removeDecorator(backingField, DecoratorNames.TRACE); - const metaField = this.metaField(originalName); - metaField.setAnnotations([annotation(DecoratorNames.JSONSTRINGIFYIGNORE), annotation(DecoratorNames.JSONPARSEIGNORE)]); - return [backingField, metaField]; + metaField(originalName: string, newName: string): arkts.ClassProperty { + const field = super.metaField(originalName, newName); + field.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); + return field; } - createGetter( - originalName: string, - newName: string, - methodModifier: arkts.Es2pandaModifierFlags - ): arkts.MethodDefinition { - const classIdent: arkts.Identifier = arkts.factory.createIdentifier(this.classScopeInfo.className); - ImportCollector.getInstance().collectImport(StateManagementTypes.UI_UTILS); - const observedMember: arkts.Expression = this.isStatic - ? uiFactory.generateMemberExpression(classIdent.clone(), newName) - : generateThisBacking(newName); - const returnMember: arkts.ReturnStatement = arkts.factory.createReturnStatement( - arkts.factory.createCallExpression( - uiFactory.generateMemberExpression( - arkts.factory.createIdentifier(StateManagementTypes.UI_UTILS), - StateManagementTypes.MAKE_OBSERVED - ), - [ - this.property.value - ? observedMember - : arkts.factory.createTSAsExpression(observedMember, this.propertyType?.clone(), false), - ], - undefined, - false, - false - ) - ); - const body = arkts.factory.createBlockStatement([this.createAddRef(originalName, classIdent), returnMember]); - return uiFactory.createMethodDefinition({ - kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, - key: arkts.factory.createIdentifier(originalName), - function: { - body: body, - returnTypeAnnotation: this.propertyType, - modifiers: methodModifier, - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_GETTER, - }, - modifiers: methodModifier, - }); + getter(originalName: string, newName: string): arkts.MethodDefinition { + return getterWithObservedV2TraceProperty.bind(this)(originalName, newName); } - createSetter( - originalName: string, - newName: string, - methodModifier: arkts.Es2pandaModifierFlags - ): arkts.MethodDefinition { - const ifEqualsNewValue: arkts.IfStatement = this.setterIfEqualsNewValue(originalName, newName); - const body = arkts.factory.createBlockStatement([ifEqualsNewValue]); - const param = arkts.factory.createETSParameterExpression( - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE, this.propertyType), - false, - undefined - ); - - return uiFactory.createMethodDefinition({ - kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET, - key: arkts.factory.createIdentifier(originalName), - function: { - body: body, - params: [param], - modifiers: methodModifier, - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER, - }, - modifiers: methodModifier, - }); + setter(originalName: string, newName: string): arkts.MethodDefinition { + return setterWithObservedV2TraceProperty.bind(this)(originalName, newName); } +} - transformGetterSetter(originalName: string, newName: string): void { - const methodModifier = this.isStatic - ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC - : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; - const newGetter = this.createGetter(originalName, newName, methodModifier); - const newSetter = this.createSetter(originalName, newName, methodModifier); - if (this.hasImplement) { - { - const idx: number = this.classScopeInfo.getters.findIndex( - (getter) => getter.id?.name === originalName - ); - const originGetter: arkts.MethodDefinition = this.classScopeInfo.getters[idx]; - const originSetter: arkts.MethodDefinition = originGetter.overloads[0]; - - const updatedSetter = arkts.factory.updateMethodDefinition( - originSetter, - originSetter.kind, - newSetter.id?.clone(), - arkts.factory.createFunctionExpression(newSetter.id?.clone(), newSetter.function! - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_OVERLOAD) - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD) - ), - originSetter.modifiers, - false, - originSetter.overloads - ); +export class ObservedV2TraceCachedTranslator + extends ObservedPropertyCachedTranslator + implements IObservedV2TraceTranslator +{ + traceDecorator: DecoratorNames.TRACE = DecoratorNames.TRACE; + className: string; + isTraced?: boolean; + isStatic?: boolean; + propertyModifier: arkts.Es2pandaModifierFlags = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + protected hasBackingField: boolean = true; + protected hasMetaField: boolean = true; + protected hasGetterSetter: boolean = true; - const updateGetter: arkts.MethodDefinition = arkts.factory.updateMethodDefinition( - originGetter, - originGetter.kind, - newGetter.id?.clone(), - arkts.factory.createFunctionExpression(newGetter.id?.clone(), newGetter.function! - .addFlag(arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD) - ), - originGetter.modifiers, - false, - [updatedSetter] - ); - this.classScopeInfo.getters[idx] = updateGetter; - } - } else { - this.classScopeInfo.getters.push(...[newGetter, newSetter]); + constructor(options: ObservedPropertyCachedTranslatorOptions) { + super(options); + this.className = this.propertyInfo.classInfo?.name!; + this.hasImplement = !!this.propertyInfo.name?.startsWith(ObservedNames.PROPERTY_PREFIX); + this.isTraced = !!this.propertyInfo.annotationInfo?.hasTrace; + this.isStatic = arkts.hasModifierFlag(this.property, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC); + if (this.isStatic) { + this.propertyModifier = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC; } + checkObservedWhenInterop(this.property); } - metaField(originalName: string): arkts.ClassProperty { - collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META); - return arkts.factory.createClassProperty( - arkts.factory.createIdentifier(`${StateManagementTypes.META}_${originalName}`), - factory.generateStateMgmtFactoryCall(StateManagementTypes.MAKE_MUTABLESTATE_META, undefined, [], false), - uiFactory.createTypeReferenceFromString(StateManagementTypes.MUTABLE_STATE_META), - this.isStatic - ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC - : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); + translateMember(): arkts.AstNode[] { + if (!this.isTraced) { + return [this.property]; + } + return super.translateMember(); } - createAddRef(originalName: string, classIdent: arkts.Identifier): arkts.ExpressionStatement { - const metaName: string = `${StateManagementTypes.META}_${originalName}`; - const conditionalAddRef = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(generateThisBacking(ObservedNames.CONDITIONAL_ADD_REF), [ - generateThisBacking(metaName), - ], undefined, false, false) - ); - const metaAddRef = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression( - uiFactory.generateMemberExpression( - uiFactory.generateMemberExpression(classIdent.clone(), metaName), - ObservedNames.ADD_REF - ), - [], - undefined, - false, - false - ) - ); - return this.isStatic ? metaAddRef : conditionalAddRef; + metaField(originalName: string, newName: string): arkts.ClassProperty { + const field = super.metaField(originalName, newName); + field.setAnnotations([ + annotation(DecoratorNames.JSONSTRINGIFYIGNORE), + annotation(DecoratorNames.JSONPARSEIGNORE), + ]); + return field; } - setterIfEqualsNewValue(originalName: string, newName: string): arkts.IfStatement { - const classIdent: arkts.Identifier = arkts.factory.createIdentifier(this.classScopeInfo.className); - const metaName: string = `${StateManagementTypes.META}_${originalName}`; - const backingValue: arkts.Expression = generateThisBacking(newName); - const metaValue: arkts.Expression = generateThisBacking(metaName); - const staticMetaValue: arkts.Expression = uiFactory.generateMemberExpression(classIdent.clone(), metaName); - const staticBackingValue: arkts.Expression = uiFactory.generateMemberExpression(classIdent.clone(), newName); - const setNewValue = arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - this.isStatic ? staticBackingValue : backingValue, - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); - - const fireChange = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression( - arkts.factory.createMemberExpression( - this.isStatic ? staticMetaValue.clone() : metaValue.clone(), - arkts.factory.createIdentifier(ObservedNames.FIRE_CHANGE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - [], - undefined, - false, - false - ) - ); - - const subscribingWatches = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(generateThisBacking(ObservedNames.EXECUATE_WATCHES), [ - arkts.factory.createStringLiteral(originalName), - ], undefined, false, false) - ); + getter(originalName: string, newName: string): arkts.MethodDefinition { + return getterWithObservedV2TraceProperty.bind(this)(originalName, newName); + } - const consequentArr = this.isStatic ? [setNewValue, fireChange] : [setNewValue, fireChange, subscribingWatches]; - return arkts.factory.createIfStatement( - arkts.factory.createBinaryExpression( - this.isStatic ? staticBackingValue.clone() : backingValue.clone(), - arkts.factory.createIdentifier(ObservedNames.NEW_VALUE), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NOT_STRICT_EQUAL - ), - arkts.factory.createBlockStatement(consequentArr) - ); + setter(originalName: string, newName: string): arkts.MethodDefinition { + return setterWithObservedV2TraceProperty.bind(this)(originalName, newName); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/once.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/once.ts index 122803c209d7dcd0afba9d6cf4cce13863184dff..83009339af6f594bfc82f40783d0f6af9f2c3bae 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/once.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/once.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { createGetter, createSetter2, @@ -25,125 +25,81 @@ import { hasDecorator, collectStateManagementTypeImport, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; -export class OnceTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); - } +export class OnceTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.ONCE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PARAM_ONCE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - } - - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.ONCE_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; - } - - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + constructor(options: PropertyTranslatorOptions) { + super(options); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); - } +export class OnceCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.ONCE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PARAM_ONCE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - factory.generateInitializeValue(this.property, this.propertyType, originalName), - ]; - collectStateManagementTypeImport(StateManagementTypes.ONCE_DECORATED); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_PARAM_ONCE, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + constructor(options: PropertyCachedTranslatorOptions) { + super(options); } } export class OnceInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.ONCE; + /** + * @deprecated + */ static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.ONCE)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.ONCE)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.ONCE); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.ONCE); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IParamOnceDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Once` and a setter with `@Once` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.ONCE, metadata); - } +export class OnceCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.ONCE; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IParamOnceDecoratedVariable | undefined`. - * - * @param property expecting property with `@Once`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.ONCE); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasOnce; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/param.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/param.ts index d2d0f4dfd433f1a72d6513293cadd82ce91437df..7367ea4ee8ec71be72dde1879f942b2cd60ef996 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/param.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/param.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { CustomComponentNames } from '../utils'; import { createGetter, @@ -25,139 +25,81 @@ import { hasDecorator, collectStateManagementTypeImport, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; -export class ParamTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); - } +export class ParamTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PARAM_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PARAM; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = false; - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - const updateStruct: arkts.AstNode = this.generateUpdateStruct(generateThisBacking(newName), originalName); - PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); - } - - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.PARAM_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - } - return [field, getter]; - } - - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + constructor(options: PropertyTranslatorOptions) { + super(options); } +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - factory.generateInitializeValue(this.property, this.propertyType, originalName), - ]; - collectStateManagementTypeImport(StateManagementTypes.PARAM_DECORATED); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_PARAM, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); - } +export class ParamCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PARAM_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PARAM; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = false; - generateUpdateStruct(mutableThis: arkts.Expression, originalName: string): arkts.AstNode { - const member: arkts.MemberExpression = arkts.factory.createMemberExpression( - arkts.factory.createTSNonNullExpression(mutableThis), - arkts.factory.createIdentifier(StateManagementTypes.UPDATE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); - const asExpression = arkts.factory.createTSAsExpression( - factory.createNonNullOrOptionalMemberExpression( - CustomComponentNames.COMPONENT_INITIALIZERS_NAME, - originalName, - false, - true - ), - this.propertyType, - false - ); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(asExpression, { ...metadata, isWithinTypeParams: true }); - } - return factory.createIfInUpdateStruct(originalName, member, [asExpression]); + constructor(options: PropertyCachedTranslatorOptions) { + super(options); } } export class ParamInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.PARAM; + /** + * @deprecated + */ static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PARAM)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PARAM)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.PARAM); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PARAM); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IParamDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Param` and a setter with `@Param` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PARAM, metadata); - } +export class ParamCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.PARAM; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IParamDecoratedVariable | undefined`. - * - * @param property expecting property with `@Param`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PARAM); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasParam; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/propRef.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/propRef.ts index 9371f6e35b0a49fcee7ae657bf45c4f6332bdb29..561fdca99eaef6175d4a939ebd95651e99f730fe 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/propRef.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/propRef.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { CustomComponentNames } from '../utils'; import { generateToRecord, @@ -27,159 +27,83 @@ import { collectStateManagementTypeImport, hasDecorator, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; - -export class PropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); - } +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; - cacheTranslatedInitializer(newName: string, originalName: string): void { - const mutableThis: arkts.Expression = generateThisBacking(newName); - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - const updateStruct: arkts.AstNode = this.generateUpdateStruct(mutableThis, originalName); - PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } - } - - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.PROP_REF_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; - } - - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); - } +export class PropRefTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - factory.generateInitializeValue(this.property, this.propertyType, originalName), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.PROP_REF_DECORATED); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_PROP_REF, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); - } +export class PropRefCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = true; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - generateUpdateStruct(mutableThis: arkts.Expression, originalName: string): arkts.AstNode { - const member: arkts.MemberExpression = arkts.factory.createMemberExpression( - arkts.factory.createTSNonNullExpression(mutableThis), - arkts.factory.createIdentifier(StateManagementTypes.UPDATE), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); - const asExpression = arkts.factory.createTSAsExpression( - factory.createNonNullOrOptionalMemberExpression( - CustomComponentNames.COMPONENT_INITIALIZERS_NAME, - originalName, - false, - true - ), - this.propertyType, - false - ); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(asExpression, { ...metadata, isWithinTypeParams: true }); - } - return factory.createIfInUpdateStruct(originalName, member, [asExpression]); + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } } export class PropRefInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.PROP_REF; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.PROP_REF); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROP_REF); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IPropRefDecoratedVariable | undefined`. - * - * @param method expecting getter with `@PropRef` and a setter with `@PropRef` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PROP_REF, metadata); - } +export class PropRefCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.PROP_REF; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IPropRefDecoratedVariable | undefined`. - * - * @param property expecting property with `@PropRef`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROP_REF); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasPropRef; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/provide.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/provide.ts index 383cead5d9cd0719f6e6485dc987dbcf8b6c9525..c6a3f6fca8ee4c08c40806ec4bdc6a3d8f2953f7 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/provide.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/provide.ts @@ -16,8 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { CustomComponentNames } from '../utils'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { createGetter, generateToRecord, @@ -28,134 +27,130 @@ import { ProvideOptions, hasDecorator, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records/struct-interface-property'; -export class ProvideTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithProvideProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(originalName, newName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const options: undefined | ProvideOptions = getValueInProvideAnnotation(this.property); + const alias: string = options?.alias ?? originalName; + const allowOverride: boolean = options?.allowOverride ?? false; + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + arkts.factory.createStringLiteral(alias), + factory.generateInitializeValue(this.property, this.propertyType, originalName), + arkts.factory.createBooleanLiteral(allowOverride), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); } + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.PROVIDE_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; +export class ProvideTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROVIDE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROVIDE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateGetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithProvideProperty.bind(this)(newName, originalName, metadata); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); +export class ProvideCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROVIDE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROVIDE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - generateInitializeStruct(originalName: string, newName: string): arkts.Statement { - const options: undefined | ProvideOptions = getValueInProvideAnnotation(this.property); - const alias: string = options?.alias ?? originalName; - const allowOverride: boolean = options?.allowOverride ?? false; - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - arkts.factory.createStringLiteral(alias), - factory.generateInitializeValue(this.property, this.propertyType, originalName), - arkts.factory.createBooleanLiteral(allowOverride), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_PROVIDE, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithProvideProperty.bind(this)(newName, originalName, metadata); } } export class ProvideInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.PROVIDE; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.PROVIDE); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROVIDE); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `ProvideDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Provide` and a setter with `@Provide` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PROVIDE, metadata); - } +export class ProvideCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.PROVIDE; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `ProvideDecoratedVariable | undefined`. - * - * @param property expecting property with `@Provide`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROVIDE); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasProvide; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/provider.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/provider.ts index fe0cd600c8fcdd20ad3f4e082165ef60a59090dd..b78f30cd48f613e6ea0999d09fd5c57374be7352 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/provider.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/provider.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; import { createGetter, createSetter2, @@ -25,127 +25,123 @@ import { hasDecorator, getValueInAnnotation, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { AstNodeCacheValueMetadata } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records/struct-interface-property'; -export class ProviderTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithProviderProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(originalName), + arkts.factory.createStringLiteral( + getValueInAnnotation(this.property, DecoratorNames.PROVIDER) ?? originalName + ), + this.property.value!, + ]; + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(originalName, newName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - } +export class ProviderTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROVIDER_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROVIDER; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.PROVIDER_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + constructor(options: PropertyTranslatorOptions) { + super(options); } - translateGetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithProviderProperty.bind(this)(newName, originalName, metadata); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); +export class ProviderCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.PROVIDER_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_PROVIDER; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); } - generateInitializeStruct(originalName: string, newName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - arkts.factory.createStringLiteral( - getValueInAnnotation(this.property, DecoratorNames.PROVIDER) ?? originalName - ), - this.property.value!, - ]; - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_PROVIDER, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithProviderProperty.bind(this)(newName, originalName, metadata); } } export class ProviderInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.PROVIDER; + /** + * @deprecated + */ static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { - if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROVIDER)) { - return true; - } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROVIDER)) { - return true; + if (arkts.isMethodDefinition(node)) { + return checkIsNameStartWithBackingField(node.id) && hasDecorator(node, DecoratorNames.PROVIDER); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.PROVIDER); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IProviderDecoratedVariable | undefined`. - * - * @param method expecting getter with `@Provider` and a setter with `@Provider` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PROVIDER, metadata); - } +export class ProviderCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.PROVIDER; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IProviderDecoratedVariable | undefined`. - * - * @param property expecting property with `@Provider`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROVIDER); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasProvider; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/regularProperty.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index df84641debe76cce544d82bb836c422c6ca158f2..56db90cd8d1bdfc16002adf547242783e792f1c2 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -15,149 +15,223 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, generateToRecord, generateThisBacking, createSetter2, isCustomDialogController, findCachedMemoMetadata } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; +import { NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + createGetter, + generateToRecord, + generateThisBacking, + createSetter2, + isCustomDialogController, + findCachedMemoMetadata, +} from './utils'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyTranslator, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; import { factory as UIFactory } from '../ui-factory'; import { CustomComponentNames, optionsHasField } from '../utils'; -import { NodeCache } from '../../common/node-cache'; - -export class RegularPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { PropertyFactoryCallTypeCache } from '../memo-collect-cache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; + +function initializeStructWithRegularProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string +): arkts.Statement { + const value = this.property.value ?? arkts.factory.createUndefinedLiteral(); + const binaryItem = arkts.factory.createBinaryExpression( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + originalName + ), + value ?? arkts.factory.createUndefinedLiteral(), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING + ); + const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + binaryItem, + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ); + return arkts.factory.createExpressionStatement(assign); +} + +function initializeStructWithCustomDialogControllerInit( + this: BasePropertyTranslator, + newName: string, + originalName: string +): arkts.Statement { + const value = this.property.value ?? arkts.factory.createUndefinedLiteral(); + const thisValue: arkts.Expression = generateThisBacking(newName, false, false); + return arkts.factory.createIfStatement( + factory.createBlockStatementForOptionalExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), + optionsHasField(originalName) + ), + arkts.factory.createBlockStatement([ + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + thisValue, + UIFactory.generateMemberExpression( + arkts.factory.createTSNonNullExpression( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME) + ), + originalName + ), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ), + ), + ]), + arkts.factory.createBlockStatement([ + arkts.factory.createIfStatement( + arkts.factory.createUnaryExpression( + thisValue, + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EXCLAMATION_MARK + ), + arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + thisValue, + value, + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ) + ), + ]) + ); +} + +function getterWithRegularProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.MethodDefinition { + const thisValue: arkts.Expression = generateThisBacking(newName, false, false); + const getter: arkts.MethodDefinition = createGetter( + originalName, + this.propertyType, + getGetterReturnValue.bind(this)(thisValue, metadata), + this.isMemoCached, + false, + metadata + ); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(getter, metadata); + } + return getter; +} + +function setterWithRegularProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.MethodDefinition { + const thisValue: arkts.Expression = generateThisBacking(newName, false, false); + const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + thisValue, + arkts.factory.createIdentifier('value'), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + ) + ); + const setter: arkts.MethodDefinition = createSetter2(originalName, this.propertyType, thisSet); + if (this.isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(setter, metadata); } + return setter; +} - cacheTranslatedInitializer(newName: string, originalName: string): void { - const value = this.property.value ?? arkts.factory.createUndefinedLiteral(); - let initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName, value); - const thisValue: arkts.Expression = generateThisBacking(newName, false, false); +function getGetterReturnValue( + this: BasePropertyTranslator, + thisValue: arkts.Expression, + metadata?: AstNodeCacheValueMetadata +): arkts.Expression { + if (!this.propertyType) { + return thisValue; + } + const newType = this.propertyType.clone(); + const returnVale = arkts.factory.createTSAsExpression(thisValue, newType, false); + if (this.isMemoCached) { + PropertyFactoryCallTypeCache.getInstance().collect({ node: newType, metadata }); + } + return returnVale; +} + +export class RegularPropertyTranslator extends PropertyTranslator { + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + let initializeStruct: arkts.Statement | undefined; if ( !!this.propertyType && !!this.structInfo.annotations.customdialog && isCustomDialogController(this.propertyType) ) { - initializeStruct = this.generateControllerInit(originalName, thisValue, value); - } - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); + initializeStruct = initializeStructWithCustomDialogControllerInit.bind(this)(newName, originalName); + } else { + initializeStruct = initializeStructWithRegularProperty.bind(this)(newName, originalName); } + return initializeStruct; } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, false); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - thisValue, - arkts.factory.createIdentifier('value'), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, this.getGetterReturnValue(thisValue)); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return getterWithRegularProperty.bind(this)(newName, originalName, metadata); } - getGetterReturnValue(thisValue: arkts.Expression): arkts.Expression { - if (!this.propertyType) { - return thisValue; - } - const returnVale = arkts.factory.createTSAsExpression(thisValue, this.propertyType, false); - if (NodeCache.getInstance().has(this.property)) { - const metadata = NodeCache.getInstance().get(this.property)?.metadata; - NodeCache.getInstance().collect(returnVale, { ...metadata, isWithinTypeParams: true }); - } - return returnVale; + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return setterWithRegularProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); - } +export class RegularPropertyCachedTranslator extends PropertyCachedTranslator { + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + let initializeStruct = initializeStructWithRegularProperty.bind(this)(newName, originalName); + if ( + !!this.propertyType && + !!this.propertyInfo.structInfo?.annotationInfo?.hasCustomDialog && + isCustomDialogController(this.propertyType) + ) { + initializeStruct = initializeStructWithCustomDialogControllerInit.bind(this)(newName, originalName); + } else { + initializeStruct = initializeStructWithRegularProperty.bind(this)(newName, originalName); + } + return initializeStruct; } - generateInitializeStruct(newName: string, originalName: string, value: arkts.Expression): arkts.Statement { - const binaryItem = arkts.factory.createBinaryExpression( - factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), - originalName - ), - value ?? arkts.factory.createUndefinedLiteral(), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING - ); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - binaryItem, - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return getterWithRegularProperty.bind(this)(newName, originalName, metadata); } - generateControllerInit(originalName: string, thisValue: arkts.Expression, value: arkts.Expression): arkts.Statement { - return arkts.factory.createIfStatement( - factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), - optionsHasField(originalName) - ), - arkts.factory.createBlockStatement([ - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - thisValue, - UIFactory.generateMemberExpression( - arkts.factory.createTSNonNullExpression( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME) - ), - originalName - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ), - ]), - arkts.factory.createBlockStatement([ - arkts.factory.createIfStatement( - arkts.factory.createUnaryExpression( - thisValue, - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EXCLAMATION_MARK - ), - arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - thisValue, - value, - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ) - ), - ]) - ); + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + return setterWithRegularProperty.bind(this)(newName, originalName, metadata); } } @@ -170,3 +244,18 @@ export class RegularInterfaceTranslator extend return true; } } + +export class RegularCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + translateProperty(): T { + return this.property; + } + + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return true; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/require.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/require.ts new file mode 100644 index 0000000000000000000000000000000000000000..cff4dcbfa25ef9d45414052687a730d691543efa --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/require.ts @@ -0,0 +1,61 @@ +/* + * 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 { backingField, expectName } from '../../common/arkts-utils'; +import { NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + createGetter, + generateToRecord, + generateThisBacking, + createSetter2, + isCustomDialogController, + findCachedMemoMetadata, +} from './utils'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyTranslator, +} from './base'; +import { factory } from './factory'; +import { PropertyCache } from './cache/propertyCache'; +import { factory as UIFactory } from '../ui-factory'; +import { CustomComponentNames, hasNullOrUndefinedType, optionsHasField } from '../utils'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { RegularPropertyCachedTranslator, RegularPropertyTranslator } from './regularProperty'; + +export class RequireTranslator extends RegularPropertyTranslator { + protected shouldWrapPropertyType: boolean = false; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; +} + +export class RequireCachedTranslator extends RegularPropertyCachedTranslator { + protected shouldWrapPropertyType: boolean = false; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/state.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/state.ts index 51432059b39c743cfc1c4ccf6f13141d911809d6..8aed0981905f587eaa0e226cb4cb148d1e89a10a 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/state.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/state.ts @@ -16,140 +16,83 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; +import { DecoratorNames, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { hasDecorator, findCachedMemoMetadata, checkIsNameStartWithBackingField } from './utils'; import { - generateToRecord, - createGetter, - createSetter2, - generateThisBacking, - generateGetOrSetCall, - hasDecorator, - collectStateManagementTypeImport, - findCachedMemoMetadata, -} from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; -export class StateTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); - } +export class StateTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STATE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STATE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } - } - - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.STATE_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; - } - - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } +} - translateSetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); - } +export class StateCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STATE_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STATE; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(originalName), - factory.generateInitializeValue(this.property, this.propertyType, originalName), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.STATE_DECORATED); - const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_STATE, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ); - return arkts.factory.createExpressionStatement(assign); + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } } export class StateInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.STATE; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.STATE); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STATE); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `StateDecoratedVariable | undefined`. - * - * @param method expecting getter with `@State` and a setter with `@State` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.STATE, metadata); - } +export class StateCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.STATE; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `StateDecoratedVariable | undefined`. - * - * @param property expecting property with `@State`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STATE); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasState; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/staticProperty.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/staticProperty.ts index c36c9781adf7de7d64955654f23554e7a1926b5a..d19a7e2d07764dbce3497aae36e1d2e3d0190c24 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/staticProperty.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/staticProperty.ts @@ -16,43 +16,102 @@ import * as arkts from '@koalaui/libarkts'; import { createGetter, createSetter, hasDecorator } from './utils'; -import { PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { PropertyCachedTranslator, PropertyTranslator } from './base'; import { backingField, expectName } from '../../common/arkts-utils'; -import { isStatic } from '../../ui-plugins/utils'; +import { isStatic } from '../utils'; import { DecoratorNames } from '../../common/predefines'; +import { StructPropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata } from '../../common/node-cache'; + +export class StaticPropertyTranslator extends PropertyTranslator { + protected hasInitializeStruct: boolean = false; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = false; + protected hasField: boolean = true; + protected hasGetter: boolean = false; + protected hasSetter: boolean = false; -export class StaticPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); return this.translateWithoutInitializer(newName, originalName); } - cacheTranslatedInitializer(newName: string, originalName: string): void {} + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + return this.property; + } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - return [this.property]; + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + throw new Error(`static property ${originalName} has no getter.`); } - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + throw new Error(`static property ${originalName} has no setter.`); } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - left: arkts.MemberExpression - ): arkts.MethodDefinition { - const right: arkts.Identifier = arkts.factory.createIdentifier('value'); - return createSetter(originalName, typeAnnotation, left, right); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return undefined; } static canBeStaticTranslate(node: arkts.ClassProperty): boolean { return isStatic(node) && !hasDecorator(node, DecoratorNames.LOCAL); } } + +export class StaticPropertyCachedTranslator extends PropertyCachedTranslator { + translateMember(): arkts.AstNode[] { + if (!this.propertyInfo || !this.propertyInfo.structInfo) { + return []; + } + if (!this.propertyInfo.name) { + return []; + } + const originalName = this.propertyInfo.name; + const newName: string = backingField(originalName); + const res = this.translateWithoutInitializer(newName, originalName); + return res; + } + + protected cacheTranslatedInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): void {} + + protected translateWithoutInitializer( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.AstNode[] { + const field = this.field(newName, originalName, metadata); + return [field]; + } + + field(newName: string, originalName?: string, metadata?: AstNodeCacheValueMetadata): arkts.ClassProperty { + return this.property; + } + + getter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + throw new Error(`static property ${originalName} has no getter.`); + } + + setter(newName: string, originalName: string, metadata?: AstNodeCacheValueMetadata): arkts.MethodDefinition { + throw new Error(`static property ${originalName} has no setter.`); + } + + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return undefined; + } + + static canBeStaticTranslate(node: arkts.ClassProperty, propertyInfo: StructPropertyInfo): boolean { + return isStatic(node) && !propertyInfo.annotationInfo?.hasLocal; + } +} diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts index 07a7bbe66ff919783f0f72cb959627a45463d9a6..13c432b82dc8a18b2dc99c943915b4ff3a7ecc20 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/storagePropRef.ts @@ -16,9 +16,17 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { DecoratorNames, GetSetTypes, NodeCacheNames, StateManagementTypes } from '../../common/predefines'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { generateToRecord, createGetter, @@ -29,142 +37,129 @@ import { hasDecorator, getValueInAnnotation, findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; - -export class StoragePropRefTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records'; +import { AstNodeCacheValueMetadata } from '../../common/node-cache'; - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithStoragePropRefProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const storagePropValueStr: string | undefined = getValueInAnnotation( + this.property, + DecoratorNames.STORAGE_PROP_REF + ); + if (!storagePropValueStr) { + return undefined; } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(storagePropValueStr), + arkts.factory.createStringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); + } + collectStateManagementTypeImport(this.stateManagementType); + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION + ) + ); +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const storagePropValueStr: string | undefined = getValueInAnnotation( - this.property, - DecoratorNames.STORAGE_PROP_REF - ); - if (!storagePropValueStr) { - throw new Error('StoragePropRef required only one value!!'); - } - - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(storagePropValueStr), - arkts.factory.createStringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.STORAGE_PROP_REF_DECORATED); +export class StoragePropRefTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STORAGE_PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STORAGE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_STORAGE_PROP_REF, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - ) - ); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.STORAGE_PROP_REF_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithStoragePropRefProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); +export class StoragePropRefCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STORAGE_PROP_REF_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STORAGE_PROP_REF; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithStoragePropRefProperty.bind(this)(newName, originalName, metadata); } } export class StoragePropRefInterfaceTranslator< - T extends InterfacePropertyTypes + T extends InterfacePropertyTypes, > extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } + protected decorator: DecoratorNames = DecoratorNames.STORAGE_PROP_REF; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STORAGE_PROP_REF); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `IStoragePropRefDecoratedVariable | undefined`. - * - * @param method expecting getter with `@StoragePropRef` and a setter with `@StoragePropRef` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.STORAGE_PROP_REF, metadata); - } +export class StoragePropRefCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.STORAGE_PROP_REF; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `IStoragePropRefDecoratedVariable | undefined`. - * - * @param property expecting property with `@StoragePropRef`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STORAGE_PROP_REF); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return ( + !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasStoragePropRef + ); } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/storagelink.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/storagelink.ts index f06ba288d50d7ef00ebbe6d74458bed48c4517c2..495a514352d15b0385ced078707081d93d868f60 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/storagelink.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/storagelink.ts @@ -15,153 +15,136 @@ import * as arkts from '@koalaui/libarkts'; -import { backingField, expectName, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; -import { DecoratorNames, GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; -import { GetterSetter, InitializerConstructor } from './types'; +import { DecoratorNames, StateManagementTypes } from '../../common/predefines'; +import { + BasePropertyTranslator, + InterfacePropertyCachedTranslator, + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyCachedTranslator, + PropertyCachedTranslatorOptions, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { - generateToRecord, - createGetter, - createSetter2, generateThisBacking, - generateGetOrSetCall, collectStateManagementTypeImport, hasDecorator, getValueInAnnotation, - findCachedMemoMetadata, + checkIsNameStartWithBackingField, } from './utils'; import { factory } from './factory'; -import { PropertyCache } from './cache/propertyCache'; -import { NodeCache } from '../../common/node-cache'; - -export class StorageLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { - translateMember(): arkts.AstNode[] { - const originalName: string = expectName(this.property.key); - const newName: string = backingField(originalName); +import { AstNodeCacheValueMetadata } from '../../common/node-cache'; +import { CustomComponentInterfacePropertyInfo } from '../../collectors/ui-collectors/records/struct-interface-property'; - this.cacheTranslatedInitializer(newName, originalName); - return this.translateWithoutInitializer(newName, originalName); +function initializeStructWithStorageLinkProperty( + this: BasePropertyTranslator, + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata +): arkts.Statement | undefined { + if (!this.stateManagementType || !this.makeType) { + return undefined; } - - cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.Statement = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); - if (!!this.structInfo.annotations?.reusable) { - const toRecord = generateToRecord(newName, originalName); - PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); - } + const storageLinkValueStr: string | undefined = getValueInAnnotation(this.property, DecoratorNames.STORAGE_LINK); + if (!storageLinkValueStr) { + return undefined; + } + const args: arkts.Expression[] = [ + arkts.factory.createStringLiteral(storageLinkValueStr), + arkts.factory.createStringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + if (this.hasWatch) { + factory.addWatchFunc(args, this.property); } + collectStateManagementTypeImport(this.stateManagementType); + return arkts.factory.createExpressionStatement( + arkts.factory.createAssignmentExpression( + generateThisBacking(newName), + factory.generateStateMgmtFactoryCall(this.makeType, this.propertyType?.clone(), args, true, metadata), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, + ) + ); +} - generateInitializeStruct(newName: string, originalName: string): arkts.Statement { - const storageLinkValueStr: string | undefined = getValueInAnnotation( - this.property, - DecoratorNames.STORAGE_LINK - ); - if (!storageLinkValueStr) { - throw new Error('StorageLink required only one value!!'); - } +export class StorageLinkTranslator extends PropertyTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STORAGE_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STORAGE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; - const args: arkts.Expression[] = [ - arkts.factory.createStringLiteral(storageLinkValueStr), - arkts.factory.createStringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; - factory.judgeIfAddWatchFunc(args, this.property); - collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_DECORATED); - return arkts.factory.createExpressionStatement( - arkts.factory.createAssignmentExpression( - generateThisBacking(newName), - factory.generateStateMgmtFactoryCall( - StateManagementTypes.MAKE_STORAGE_LINK, - this.propertyType?.clone(), - args, - true, - this.isMemoCached ? findCachedMemoMetadata(this.property, true) : undefined - ), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION - ) - ); + constructor(options: PropertyTranslatorOptions) { + super(options); + this.hasWatch = hasDecorator(this.property, DecoratorNames.WATCH); } - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.STORAGE_LINK_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); - const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); - const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( - generateGetOrSetCall(thisValue, GetSetTypes.SET) - ); - const getter: arkts.MethodDefinition = this.translateGetter(originalName, this.propertyType, thisGet); - const setter: arkts.MethodDefinition = this.translateSetter(originalName, this.propertyType, thisSet); - if (this.isMemoCached) { - const metadata = findCachedMemoMetadata(this.property, false); - NodeCache.getInstance().collect(field, { ...metadata, isWithinTypeParams: true }); - NodeCache.getInstance().collect(getter, metadata); - NodeCache.getInstance().collect(setter, metadata); - } - return [field, getter, setter]; + initializeStruct( + newName: string, + originalName: string, + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithStorageLinkProperty.bind(this)(newName, originalName, metadata); } +} - translateGetter( - originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - returnValue: arkts.Expression - ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); +export class StorageLinkCachedTranslator extends PropertyCachedTranslator { + protected stateManagementType: StateManagementTypes = StateManagementTypes.STORAGE_LINK_DECORATED; + protected makeType: StateManagementTypes = StateManagementTypes.MAKE_STORAGE_LINK; + protected shouldWrapPropertyType: boolean = true; + protected hasInitializeStruct: boolean = true; + protected hasUpdateStruct: boolean = false; + protected hasToRecord: boolean = true; + protected hasField: boolean = true; + protected hasGetter: boolean = true; + protected hasSetter: boolean = true; + + constructor(options: PropertyCachedTranslatorOptions) { + super(options); + this.hasWatch = this.propertyInfo.annotationInfo?.hasWatch; } - translateSetter( + initializeStruct( + newName: string, originalName: string, - typeAnnotation: arkts.TypeNode | undefined, - statement: arkts.AstNode - ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + metadata?: AstNodeCacheValueMetadata + ): arkts.Statement | undefined { + return initializeStructWithStorageLinkProperty.bind(this)(newName, originalName, metadata); } } export class StorageLinkInterfaceTranslator extends InterfacePropertyTranslator { - translateProperty(): T { - if (arkts.isMethodDefinition(this.property)) { - this.modified = true; - return flatVisitMethodWithOverloads(this.property, this.updateStateMethodInInterface) as T; - } else if (arkts.isClassProperty(this.property)) { - this.modified = true; - return this.updateStatePropertyInInterface(this.property) as T; - } - return this.property; - } - + protected decorator: DecoratorNames = DecoratorNames.STORAGE_LINK; + /** + * @deprecated + */ 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.id) && hasDecorator(node, DecoratorNames.STORAGE_LINK); + } else if (arkts.isClassProperty(node)) { + return checkIsNameStartWithBackingField(node.key) && hasDecorator(node, DecoratorNames.STORAGE_LINK); } return false; } +} - /** - * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) - * to `StorageLinkDecoratedVariable | undefined`. - * - * @param method expecting getter with `@StorageLink` and a setter with `@StorageLink` in the overloads. - */ - private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { - const metadata = findCachedMemoMetadata(method); - return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.STORAGE_LINK, metadata); - } +export class StorageLinkCachedInterfaceTranslator< + T extends InterfacePropertyTypes, +> extends InterfacePropertyCachedTranslator { + protected decorator: DecoratorNames = DecoratorNames.STORAGE_LINK; /** - * Wrap to the type of the property (expecting an union type with `T` and `undefined`) - * to `StorageLinkDecoratedVariable | undefined`. - * - * @param property expecting property with `@StorageLink`. + * @deprecated */ - private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { - return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STORAGE_LINK); + static canBeTranslated( + node: arkts.AstNode, + metadata?: CustomComponentInterfacePropertyInfo + ): node is InterfacePropertyTypes { + return !!metadata?.name?.startsWith(StateManagementTypes.BACKING) && !!metadata.annotationInfo?.hasStorageLink; } } diff --git a/ui2abc/arkui-plugins/ui-plugins/property-translators/utils.ts b/ui2abc/arkui-plugins/ui-plugins/property-translators/utils.ts index 56f7d8656b69f368105777658821544ebb4b7023..b89ab163523a5f0c4bfc55360c349bb6eb21bb5e 100644 --- a/ui2abc/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -17,11 +17,11 @@ import * as arkts from '@koalaui/libarkts'; import { ImportCollector } from '../../common/import-collector'; import { isDecoratorAnnotation } from '../../common/arkts-utils'; import { - DecoratorIntrinsicNames, DecoratorNames, StateManagementTypes, GetSetTypes, ObservedNames, + NodeCacheNames, } from '../../common/predefines'; import { addMemoAnnotation, @@ -29,8 +29,7 @@ import { findCanAddMemoFromTypeAnnotation, } from '../../collectors/memo-collectors/utils'; import { CustomDialogNames } from '../utils'; -import { CachedMetadata } from '../../memo-plugins/memo-cache-factory'; -import { AstNodeCacheValueMetadata, NodeCache } from '../../common/node-cache'; +import { AstNodeCacheValueMetadata, NodeCacheFactory } from '../../common/node-cache'; export interface DecoratorInfo { annotation: arkts.AnnotationUsage; @@ -42,13 +41,6 @@ export interface OptionalMemberInfo { isNumeric?: boolean; } -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, @@ -109,7 +101,8 @@ export function needDefiniteOrOptionalModifier(st: arkts.ClassProperty): boolean (hasDecoratorName(st, DecoratorNames.PROP_REF) && !st.value) || (hasDecoratorName(st, DecoratorNames.PARAM) && !st.value) || (hasDecoratorName(st, DecoratorNames.EVENT) && !st.value) || - (hasDecoratorName(st, DecoratorNames.REQUIRE) && !st.value) + (hasDecoratorName(st, DecoratorNames.REQUIRE) && !st.value) || + (hasDecoratorName(st, DecoratorNames.BUILDER_PARAM) && !st.value) ); } @@ -156,13 +149,11 @@ export function createGetter( name: string, type: arkts.TypeNode | undefined, returns: arkts.Expression, - needMemo: boolean = false, - isStatic: boolean = false + isMemoCached: boolean = false, + isStatic: boolean = false, + metadata?: AstNodeCacheValueMetadata ): arkts.MethodDefinition { const returnType: arkts.TypeNode | undefined = type?.clone(); - if (needMemo && findCanAddMemoFromTypeAnnotation(returnType)) { - addMemoAnnotation(returnType); - } const body = arkts.factory.createBlockStatement([arkts.factory.createReturnStatement(returns)]); const modifiers = isStatic ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC @@ -175,13 +166,17 @@ export function createGetter( arkts.factory.createIdentifier(name), undefined ); - return arkts.factory.createMethodDefinition( + const method = arkts.factory.createMethodDefinition( arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, arkts.factory.createIdentifier(name), arkts.factory.createFunctionExpression(undefined, scriptFunction), modifiers, false ); + if (!!returnType && isMemoCached) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(returnType, metadata); + } + return method; } export function createSetter( @@ -460,7 +455,7 @@ export function getArrayFromAnnoProperty(property: arkts.AstNode): string[] | un } function getMonitorStrFromMemberExpr(node: arkts.MemberExpression): string | undefined { - const decl: arkts.AstNode | undefined = arkts.getDecl(node.property!); + const decl: arkts.AstNode | undefined = arkts.getPeerIdentifierDecl(node.property!.peer); if (!decl || !arkts.isClassProperty(decl) || !decl.value || !arkts.isETSNewClassInstanceExpression(decl.value)) { return undefined; } @@ -471,13 +466,23 @@ function getMonitorStrFromMemberExpr(node: arkts.MemberExpression): string | und return undefined; } -export function findCachedMemoMetadata(node: arkts.AstNode, shouldWrapType: boolean = true): AstNodeCacheValueMetadata | undefined { - if (!arkts.MemoNodeCache.getInstance().has(node)) { +export function findCachedMemoMetadata( + node: arkts.AstNode, + shouldWrapType: boolean = true +): AstNodeCacheValueMetadata | undefined { + if (!NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).has(node)) { return undefined; } - const metadata = arkts.MemoNodeCache.getInstance().get(node)?.metadata ?? {}; + const metadata = NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).get(node)?.metadata ?? {}; if (!!shouldWrapType) { metadata.isWithinTypeParams = true; } return metadata; } + +export function checkIsNameStartWithBackingField(node: arkts.AstNode | undefined): boolean { + if (!node || !arkts.isIdentifier(node)) { + return false; + } + return node.name.startsWith(StateManagementTypes.BACKING); +} diff --git a/ui2abc/arkui-plugins/ui-plugins/struct-translators/cache-factory.ts b/ui2abc/arkui-plugins/ui-plugins/struct-translators/cache-factory.ts new file mode 100644 index 0000000000000000000000000000000000000000..61e0ae8cc1877e18dc88c477ed47d6a1373df594 --- /dev/null +++ b/ui2abc/arkui-plugins/ui-plugins/struct-translators/cache-factory.ts @@ -0,0 +1,592 @@ +/* + * 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, + CustomComponentInfo as CustomComponentRecordInfo, + FunctionInfo, + NormalClassAnnotationInfo, + NormalClassInfo, + NormalInterfaceInfo, + NormalInterfacePropertyInfo, + StructMethodInfo, +} from '../../collectors/ui-collectors/records'; +import { + AnimationNames, + ARKUI_BUILDER_SOURCE_NAME, + CustomComponentNames, + Dollars, + NodeCacheNames, + RESOURCE_TYPE, + StateManagementTypes, +} from '../../common/predefines'; +import { collect } from '../../common/arkts-utils'; +import { MetaDataCollector } from '../../common/metadata-collector'; +import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; +import { InnerComponentInfoCache } from '../builder-lambda-translators/cache/innerComponentInfoCache'; +import { PropertyRewriteCache } from '../property-translators/cache/propertyRewriteCache'; +import { ComputedCache } from '../property-translators/cache/computedCache'; +import { MonitorCache } from '../property-translators/cache/monitorCache'; +import { PropertyCache } from '../property-translators/cache/propertyCache'; +import { CustomDialogControllerPropertyCache } from '../property-translators/cache/customDialogControllerPropertyCache'; +import { collectStateManagementTypeImport } from '../property-translators/utils'; +import { + CustomDialogNames, + getCustomComponentOptionsName, + getTypeNameFromTypeParameter, + getTypeParamsFromClassDecl, + isKnownMethodDefinition, + StructType, +} from '../utils'; +import { ConditionScopeFactory } from '../condition-scope-translators/condition-scope-factory'; +import { CacheFactory as BuilderLambdaCacheFactory } from '../builder-lambda-translators/cache-factory'; +import { factory as BuilderLambdaFactory } from '../builder-lambda-translators/factory'; +import { CacheFactory as PropertyCacheFactory } from '../property-translators/cache-factory'; +import { factory as PropertyFactory } from '../property-translators/factory'; +import { factory as UIFactory } from '../ui-factory'; +import { factory as StructFactory } from './factory'; +import { getResourceParams } from './utils'; +import { + BuilderParamClassPropertyValueCache, + CustomDialogControllerCache, + PropertyFactoryCallTypeCache, +} from '../memo-collect-cache'; +import { NodeCacheFactory } from '../../common/node-cache'; + +interface RewritedStructMethodInfo { + hasInitializeStruct?: boolean; + hasUpdateStruct?: boolean; + hasToRecord?: boolean; +} + +export function collectRewritedStructMethodInfo( + node: arkts.AstNode, + info?: RewritedStructMethodInfo +): RewritedStructMethodInfo { + const currInfo = info ?? {}; + if (!arkts.isMethodDefinition(node)) { + return currInfo; + } + const methodName = node.id!.name; + const hasInitializeStruct = methodName === CustomComponentNames.COMPONENT_INITIALIZE_STRUCT; + const hasUpdateStruct = methodName === CustomComponentNames.COMPONENT_UPDATE_STRUCT; + const hasToRecord = methodName === CustomComponentNames.COMPONENT_TO_RECORD; + return { + ...(!currInfo.hasInitializeStruct && { hasInitializeStruct }), + ...(!currInfo.hasUpdateStruct && { hasUpdateStruct }), + ...(!currInfo.hasToRecord && { hasToRecord }), + }; +} + +export class CacheFactory { + /** + * create `__initializeStruct` method. + */ + static createInitializeStruct( + optionsTypeName: string, + metadata: CustomComponentRecordInfo + ): arkts.MethodDefinition { + const updateKey: arkts.Identifier = arkts.factory.createIdentifier( + CustomComponentNames.COMPONENT_INITIALIZE_STRUCT + ); + + let body: arkts.BlockStatement | undefined; + let modifiers: arkts.Es2pandaModifierFlags = + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; + if (!metadata.isDecl) { + body = arkts.factory.createBlockStatement([ + ...ComputedCache.getInstance().getCachedComputed(metadata.name!), + ...PropertyCache.getInstance().getInitializeBody(metadata.name!), + ...MonitorCache.getInstance().getCachedMonitors(metadata.name!), + ]); + modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; + } + const contentParam = UIFactory.createContentParameter(); + const scriptFunction: arkts.ScriptFunction = arkts.factory + .createScriptFunction( + body, + undefined, + [UIFactory.createInitializersOptionsParameter(optionsTypeName), contentParam], + arkts.factory.createETSPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + modifiers, + updateKey, + undefined + ); + const newMethod = arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + updateKey, + arkts.factory.createFunctionExpression(undefined, scriptFunction), + modifiers, + false + ); + CustomDialogControllerCache.getInstance().updateAll().reset(); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(contentParam); + return newMethod; + } + + /** + * create `__updateStruct` method. + */ + static createUpdateStruct(optionsTypeName: string, metadata: CustomComponentRecordInfo): arkts.MethodDefinition { + const updateKey: arkts.Identifier = arkts.factory.createIdentifier( + CustomComponentNames.COMPONENT_UPDATE_STRUCT + ); + + let body: arkts.BlockStatement | undefined; + let modifiers: arkts.Es2pandaModifierFlags = + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE; + if (!metadata.isDecl) { + body = arkts.factory.createBlockStatement(PropertyCache.getInstance().getUpdateBody(metadata.name!)); + modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; + } + const scriptFunction: arkts.ScriptFunction = arkts.factory + .createScriptFunction( + body, + undefined, + [UIFactory.createInitializersOptionsParameter(optionsTypeName)], + arkts.factory.createETSPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + modifiers, + updateKey, + undefined + ); + + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + updateKey, + arkts.factory.createFunctionExpression(undefined, scriptFunction), + modifiers, + false + ); + } + + /** + * create `__toRecord` method when the component is decorated with @Reusable. + */ + static createToRecord(optionsTypeName: string, metadata: CustomComponentRecordInfo): arkts.MethodDefinition { + const paramsCasted = StructFactory.generateParamsCasted(optionsTypeName); + const returnRecord = arkts.factory.createReturnStatement( + arkts.ObjectExpression.createObjectExpression( + arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, + PropertyCache.getInstance().getToRecordBody(metadata.name!), + false + ) + ); + const body: arkts.BlockStatement = arkts.factory.createBlockStatement([paramsCasted, returnRecord]); + + const params = arkts.factory.createETSParameterExpression( + arkts.factory.createIdentifier('params', StructFactory.generateTypeReferenceWithTypeName('Object')), + false, + undefined + ); + + const toRecordScriptFunction = arkts.factory.createScriptFunction( + body, + undefined, + [params], + StructFactory.generateTypeRecord(), + false, + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_TO_RECORD), + undefined + ); + + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_TO_RECORD), + arkts.factory.createFunctionExpression(undefined, toRecordScriptFunction), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_OVERRIDE, + false + ); + } + + static collectStructPropertyRewriteStatements( + optionsTypeName: string, + metadata: CustomComponentRecordInfo, + scope: RewritedStructMethodInfo + ): arkts.AstNode[] { + const collections = []; + if (!scope.hasInitializeStruct) { + collections.push(this.createInitializeStruct(optionsTypeName, metadata)); + } + if (!scope.hasUpdateStruct) { + collections.push(this.createUpdateStruct(optionsTypeName, metadata)); + } + if (!scope.hasToRecord && !!metadata.annotationInfo?.hasReusable) { + collections.push(this.createToRecord(optionsTypeName, metadata)); + } + BuilderParamClassPropertyValueCache.getInstance().updateAll().reset(); + PropertyFactoryCallTypeCache.getInstance().updateAll().reset(); + return collections; + } + + /** + * transform all members in struct or custom-component declation class. + * + * @internal + */ + static transformStructMembers( + node: arkts.ClassDeclaration, + definition: arkts.ClassDefinition, + metadata: CustomComponentRecordInfo, + structType: StructType + ): void { + if (!metadata.name) { + return; + } + const body: readonly arkts.AstNode[] = definition.body; + let scopeInfo: RewritedStructMethodInfo = {}; + let hasStaticBlock: boolean = false; + const transformedBody = body.map((child: arkts.AstNode) => { + scopeInfo = collectRewritedStructMethodInfo(child, scopeInfo); + if (structType === StructType.CUSTOM_COMPONENT_DECL) { + return [child]; + } + hasStaticBlock = arkts.isClassStaticBlock(child); + const nodes = PropertyRewriteCache.getInstance().getRewriteNodes(child.peer); + if (nodes.length > 0) { + return nodes; + } + return [child]; + }); + let optionsTypeName: string | undefined; + if (structType === StructType.CUSTOM_COMPONENT_DECL) { + const [_, classOptions] = getTypeParamsFromClassDecl(node); + optionsTypeName = getTypeNameFromTypeParameter(classOptions); + } + const newStatements = this.collectStructPropertyRewriteStatements( + optionsTypeName ?? getCustomComponentOptionsName(metadata.name), + metadata, + scopeInfo + ); + const newStaticBlock = !metadata.isDecl && !hasStaticBlock ? [UIFactory.createClassStaticBlock()] : []; + const returnNodes: arkts.AstNode[] = collect(newStatements, ...transformedBody, newStaticBlock); + definition.setBody(returnNodes); + if (structType === StructType.STRUCT) { + PropertyRewriteCache.getInstance().reset(); + } + } + + /** + * add `__setDialogController__` to `@CustomDialog` struct when there is any `CustomDialogController` property. + * + * @internal + */ + static addSetDialogControllerToStruct( + definition: arkts.ClassDefinition, + metadata: CustomComponentRecordInfo, + structType: StructType + ): void { + if (!metadata.name) { + return; + } + if ( + structType === StructType.CUSTOM_COMPONENT_DECL && + metadata.name === CustomComponentNames.BASE_CUSTOM_DIALOG_NAME + ) { + definition.addProperties([StructFactory.createCustomDialogMethod(!!metadata.isDecl)]); + } else if (structType === StructType.STRUCT && !!metadata.annotationInfo?.hasCustomDialog) { + const info = CustomDialogControllerPropertyCache.getInstance().getInfo(metadata.name!); + if (!!info) { + definition.addProperties([ + StructFactory.createCustomDialogMethod( + !!metadata.isDecl, + info.propertyName, + info.controllerTypeName + ), + ]); + } + CustomDialogControllerPropertyCache.getInstance().reset(); + } + } + + /** + * transform members in custom-component class. + */ + static tranformClassMembersFromInfo( + node: arkts.ClassDeclaration, + metadata: CustomComponentRecordInfo, + structType: StructType + ): arkts.ClassDeclaration { + const definition = node.definition; + if (!definition || !metadata.name) { + return node; + } + if (structType === StructType.STRUCT && !!metadata.isDecl) { + return node; + } + this.transformStructMembers(node, definition, metadata, structType); + this.addSetDialogControllerToStruct(definition, metadata, structType); + return node; + } + + static transformAnimatableExtendMethod( + node: arkts.MethodDefinition, + metadata: FunctionInfo + ): arkts.MethodDefinition { + const name: string | undefined = metadata.name; + const func: arkts.ScriptFunction = node.function; + const params = func.params as arkts.ETSParameterExpression[]; + const body = func.body; + if (!name || !params.at(1) || !body || !arkts.isBlockStatement(body)) { + return node; + } + const funcName: arkts.StringLiteral = arkts.factory.createStringLiteral(name); + const paramValue: arkts.ETSParameterExpression = params.at(1)!; + const statements = [...body.statements]; + const lastStatement = statements.pop(); + if (!lastStatement) { + return node; + } + const createOrSetStatement = arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier(AnimationNames.CREATE_OR_SET_ANIMATABLEPROPERTY), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + [funcName, paramValue.ident!, StructFactory.createAniExtendCbArg(paramValue, statements)], + undefined, + false, + false + ) + ); + const newBody = arkts.factory.createBlockStatement([createOrSetStatement, lastStatement]); + node.function.setBody(newBody); + return node; + } + + static transformETSGlobalClassFromInfo( + node: arkts.ClassDeclaration, + metadata: NormalClassInfo + ): arkts.ClassDeclaration { + const definition = node.definition; + if (!definition) { + return node; + } + let newStatements: arkts.AstNode[] = []; + if (InnerComponentInfoCache.getInstance().isCollected()) { + const cache: InnerComponentInfoCache = InnerComponentInfoCache.getInstance(); + const names = cache.getAllComponentNames(); + const methods = BuilderLambdaCacheFactory.createAllUniqueDeclaredComponentFunctions(names, cache); + newStatements.push(...methods); + } + if (MetaDataCollector.getInstance().externalSourceName === ARKUI_BUILDER_SOURCE_NAME) { + newStatements.push(...BuilderLambdaFactory.addConditionBuilderDecls()); + } + definition.setBody([...definition.body, ...newStatements]); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).collect(definition); + return node; + } + + static transformObservedClassFromInfo( + node: arkts.ClassDeclaration, + metadata: NormalClassInfo + ): arkts.ClassDeclaration { + const definition = node.definition; + if (!definition || !metadata.name) { + return node; + } + definition.setImplements([ + ...definition.implements, + arkts.TSClassImplements.createTSClassImplements( + UIFactory.createTypeReferenceFromString(StateManagementTypes.OBSERVED_OBJECT) + ), + arkts.TSClassImplements.createTSClassImplements( + UIFactory.createTypeReferenceFromString(StateManagementTypes.SUBSCRIBED_WATCHES) + ), + ]); + definition.setBody(this.createObservedMembers(definition, metadata)); + collectStateManagementTypeImport(StateManagementTypes.OBSERVED_OBJECT); + return node; + } + + static createObservedMembers(definition: arkts.ClassDefinition, metadata: NormalClassInfo): arkts.AstNode[] { + const isDecl: boolean = arkts.hasModifierFlag(definition, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + const className: string = metadata.name!; + const classAnnoInfo: NormalClassAnnotationInfo | undefined = metadata.annotationInfo; + const isObservedV2: boolean = !!classAnnoInfo?.hasObservedV2; + const isObserved: boolean = !!classAnnoInfo?.hasObserved; + const watchMembers: arkts.AstNode[] = PropertyFactory.createWatchMembers(); + const v1RenderIdMembers: arkts.AstNode[] = PropertyFactory.createV1RenderIdMembers(isObservedV2); + const conditionalAddRef: arkts.MethodDefinition = PropertyFactory.conditionalAddRef(isObservedV2); + const metaProperty: arkts.ClassProperty[] = + isObserved && !metadata.hasTrackProperty ? [PropertyFactory.createMetaInObservedClass()] : []; + let hasConstructorToRewrite: boolean = false; + let hasStaticBlock: boolean = false; + const propertyMembers: arkts.AstNode[][] = definition.body.map((child: arkts.AstNode) => { + hasStaticBlock = arkts.isClassStaticBlock(child); + if ( + isObservedV2 && + !isDecl && + arkts.isMethodDefinition(child) && + isKnownMethodDefinition(child, CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI) + ) { + hasConstructorToRewrite = true; + return [this.rewriteObservedV2Constuctor(child, className)]; + } + const nodes = PropertyRewriteCache.getInstance().getRewriteNodes(child.peer); + if (nodes.length > 0) { + return nodes; + } + return [child]; + }); + const newConstructor = + isObservedV2 && !hasConstructorToRewrite ? [this.createNewObservedV2Constuctor(className, isDecl)] : []; + const newStaticBlock = !hasStaticBlock ? [UIFactory.createClassStaticBlock()] : []; + const returnNodes: arkts.AstNode[] = collect( + watchMembers, + v1RenderIdMembers, + conditionalAddRef, + metaProperty, + ...propertyMembers, + newConstructor, + newStaticBlock + ); + PropertyRewriteCache.getInstance().reset(); + return returnNodes; + } + + static rewriteObservedV2Constuctor(ctor: arkts.MethodDefinition, className: string): arkts.MethodDefinition { + const addConstructorNodes: arkts.Statement[] = MonitorCache.getInstance().getCachedMonitors(className); + const scriptFunc: arkts.ScriptFunction = ctor.function; + const originBody = scriptFunc.body as arkts.BlockStatement | undefined; + if (!originBody) { + scriptFunc.setBody(arkts.factory.createBlockStatement(addConstructorNodes)); + } else { + scriptFunc.setBody( + arkts.factory.updateBlockStatement(originBody, [...originBody.statements, ...addConstructorNodes]) + ); + } + return ctor; + } + + static createNewObservedV2Constuctor(className: string, isDecl: boolean): arkts.MethodDefinition { + const addConstructorNodes: arkts.Statement[] = MonitorCache.getInstance().getCachedMonitors(className); + return UIFactory.createMethodDefinition({ + key: arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI), + function: { + key: arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI), + body: isDecl ? undefined : arkts.factory.createBlockStatement(addConstructorNodes), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_CONSTRUCTOR, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + }, + kind: arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, + }); + } + + /** + * transform non-property members in custom-component class. + */ + static transformNonPropertyMembersInClassFromInfo( + member: arkts.MethodDefinition, + metadata: StructMethodInfo + ): arkts.MethodDefinition { + PropertyCacheFactory.addMemoToBuilderClassMethodFromInfo(member, metadata); + if (metadata.name === CustomComponentNames.COMPONENT_BUILD_ORI) { + addMemoAnnotation(member.function); + return ConditionScopeFactory.rewriteBuilderMethod(member); + } + return member; + } + + static transformResourceFromInfo(resourceNode: arkts.CallExpression, metadata: CallInfo): arkts.CallExpression { + const projectConfig = MetaDataCollector.getInstance().projectConfig; + const resourceInfo = MetaDataCollector.getInstance().resourceInfo; + const args: readonly arkts.Expression[] = resourceNode.arguments; + if (!projectConfig || !resourceInfo || args.length <= 0) { + return resourceNode; + } + const resourceKind: Dollars = metadata.isResourceCall!; + const firstArg: arkts.Expression = args.at(0)!; + if (arkts.isStringLiteral(firstArg)) { + return StructFactory.processStringLiteralResourceNode( + resourceNode, + resourceInfo, + projectConfig, + resourceKind, + firstArg + ); + } else if (args && args.length) { + return StructFactory.generateTransformedResourceCall( + resourceNode, + getResourceParams( + -1, + resourceKind === Dollars.DOLLAR_RAWFILE ? RESOURCE_TYPE.rawfile : -1, + Array.from(args) + ), + '', + false, + projectConfig, + resourceKind + ); + } + return resourceNode; + } + + static extendInnerComponentAttributeInterface( + node: arkts.TSInterfaceDeclaration, + metadata: NormalInterfaceInfo + ): arkts.TSInterfaceDeclaration { + if (!InnerComponentInfoCache.getInstance().isCollected() || !metadata.name) { + return node; + } + const componentName = metadata.name.replace(/Attribute$/, ''); + if (!InnerComponentInfoCache.getInstance().hasComponentName(componentName)) { + return node; + } + return BuilderLambdaCacheFactory.addDeclaredSetMethodsInAttributeInterface(node, componentName); + } + + static updateBuilderType(builderNode: arkts.MethodDefinition): arkts.MethodDefinition { + const newType: arkts.TypeNode | undefined = UIFactory.createTypeReferenceFromString( + CustomDialogNames.CUSTOM_BUILDER + ); + if (builderNode.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + const newOverLoads = builderNode.overloads.map((overload) => { + if (arkts.isMethodDefinition(overload)) { + return this.updateBuilderType(overload); + } + return overload; + }); + builderNode.setOverloads(newOverLoads); + if (!!newType) { + builderNode.function.setReturnTypeAnnotation(newType); + } + } else if (builderNode.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + const param = builderNode.function.params[0] as arkts.ETSParameterExpression; + const newParam: arkts.Expression | undefined = arkts.factory.updateETSParameterExpression( + param, + arkts.factory.createIdentifier(param.ident!.name, newType), + param.isOptional, + param.initializer, + param.annotations + ); + if (!!newParam) { + return UIFactory.updateMethodDefinition(builderNode, { function: { params: [newParam] } }); + } + } + return builderNode; + } + +} diff --git a/ui2abc/arkui-plugins/ui-plugins/struct-translators/factory.ts b/ui2abc/arkui-plugins/ui-plugins/struct-translators/factory.ts index 66853d0d7df328528a32b00737bb4c5a2498ae0f..2c1bbfe3380279e69b4724e140fbbaeb2d226e82 100644 --- a/ui2abc/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -26,12 +26,20 @@ import { isCustomDialogControllerOptions, isKnownMethodDefinition, isStatic, + StructType, } from '../utils'; 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 { BuilderFactory } from '../builder-lambda-translators/builder-factory'; -import { backingField, collect, filterDefined, flatVisitMethodWithOverloads } from '../../common/arkts-utils'; +import { + annotation, + backingField, + collect, + filterDefined, + findLastPropertyElement, + flatVisitMethodWithOverloads, +} from '../../common/arkts-utils'; import { classifyInObservedClass, classifyPropertyInInterface, @@ -43,7 +51,6 @@ import { import { CustomComponentScopeInfo, isEtsGlobalClass, - ResourceInfo, checkRawfileResource, generateResourceModuleName, generateResourceBundleName, @@ -58,10 +65,12 @@ import { ObservedAnnoInfo, getNoTransformationMembersInClass, isComputedMethod, + StructScopeInfo, + CustomComponentDeclScopeInfo, } from './utils'; import { collectStateManagementTypeImport, generateThisBacking, hasDecorator } from '../property-translators/utils'; import { findComponentAttributeInInterface } from '../builder-lambda-translators/utils'; -import { ProjectConfig, UIPluginOptions } from '../../common/plugin-context'; +import { ProjectConfig, ResourceInfo, UIPluginOptions } from '../../common/plugin-context'; import { ImportCollector } from '../../common/import-collector'; import { AnimationNames, @@ -73,18 +82,20 @@ import { RESOURCE_TYPE, ARKUI_BUILDER_SOURCE_NAME, TypeNames, + NodeCacheNames, } from '../../common/predefines'; -import { ObservedTranslator } from '../property-translators/index'; +import { BaseObservedPropertyTranslator } from '../property-translators/index'; import { addMemoAnnotation } from '../../collectors/memo-collectors/utils'; import { generateArkUICompatible } from '../interop/interop'; import { GenSymGenerator } from '../../common/gensym-generator'; -import { MethodTranslator } from '../property-translators/base'; +import { BaseMethodTranslator, MethodTranslator } from '../property-translators/base'; import { MonitorCache } from '../property-translators/cache/monitorCache'; import { PropertyCache } from '../property-translators/cache/propertyCache'; import { ComputedCache } from '../property-translators/cache/computedCache'; import { ComponentAttributeCache } from '../builder-lambda-translators/cache/componentAttributeCache'; -import { isInteropComponent } from '../interop/utils'; -import { NodeCache } from '../../common/node-cache'; +import { CustomDialogControllerBuilderCache, CustomDialogControllerCache } from '../memo-collect-cache'; +import { insertInteropComponentImports, isInteropComponent } from '../interop/utils'; +import { NodeCacheFactory } from '../../common/node-cache'; export class factory { /** @@ -523,10 +534,10 @@ export class factory { if (!scope.hasUpdateStruct) { collections.push(this.createUpdateStruct(optionsTypeName, scope)); } - if (!!scope.annotations?.reusable) { + if (scope.type === StructType.STRUCT && !!scope.annotations?.reusable) { collections.push(this.createToRecord(optionsTypeName, scope)); } - return collect(...collections, ...propertyMembers); + return collect(collections, ...propertyMembers); } /** @@ -536,9 +547,21 @@ export class factory { if (arkts.isMethodDefinition(member)) { PropertyFactory.addMemoToBuilderClassMethod(member); if (isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_BUILD_ORI)) { - addMemoAnnotation(member.function!); + addMemoAnnotation(member.function); const transformedBuildMethod = BuilderFactory.rewriteBuilderMethod(member); - NodeCache.getInstance().refresh(member, transformedBuildMethod); + // TODO check if this explicit cache is needed + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .refresh(member, transformedBuildMethod); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .refreshUpdate(member, transformedBuildMethod); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .refresh(member.function, transformedBuildMethod.function); + NodeCacheFactory.getInstance() + .getCache(NodeCacheNames.MEMO) + .refreshUpdate(member.function, transformedBuildMethod.function); return transformedBuildMethod; } return member; @@ -563,29 +586,65 @@ export class factory { if (!className) { throw new Error('Non Empty className expected for Component'); } + let updateClassDef: arkts.ClassDefinition; + if (scope.type === StructType.STRUCT) { + updateClassDef = this.transformStructMembers(definition, scope, className, classOptionsName); + } else if (scope.type === StructType.INVALID_STRUCT) { + throw new Error('Non Empty invalid class expected for Component'); + } else { + updateClassDef = this.transformCustomComponentDeclMembers(definition, scope, className, classOptionsName); + } + return arkts.factory.updateClassDeclaration(node, updateClassDef); + } + + /** + * transform members in custom-component class. + */ + static transformStructMembers( + definition: arkts.ClassDefinition, + scope: StructScopeInfo, + className: string, + classOptionsName: string | undefined + ): arkts.ClassDefinition { const body: readonly arkts.AstNode[] = definition.body; const propertyTranslators: (PropertyTranslator | MethodTranslator)[] = filterDefined( body.map((member) => classifyStructMembers(member, scope)) ); + let updateMembers: arkts.AstNode[] = []; const translatedMembers: arkts.AstNode[] = this.tranformPropertyMembers( propertyTranslators, classOptionsName ?? getCustomComponentOptionsName(className), scope ); - const updateMembers: arkts.AstNode[] = body + updateMembers = body .filter((member) => !arkts.isClassProperty(member) && !isComputedMethod(member)) .map((member: arkts.AstNode) => factory.transformNonPropertyMembersInClass(member, scope.isDecl)); - const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass( - definition, - factory.addClassStaticBlock([...translatedMembers, ...updateMembers], body) + updateMembers = factory.addClassStaticBlock(collect(translatedMembers, updateMembers), body); + const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass(definition, updateMembers); + if (!!scope.annotations.customdialog) { + updateClassDef.addProperties(factory.addControllerSetMethod(scope.isDecl, body)); + } + return updateClassDef; + } + + static transformCustomComponentDeclMembers( + definition: arkts.ClassDefinition, + scope: CustomComponentDeclScopeInfo, + className: string, + classOptionsName: string | undefined + ): arkts.ClassDefinition { + const body: readonly arkts.AstNode[] = definition.body; + const translatedMembers: arkts.AstNode[] = this.tranformPropertyMembers( + [], + classOptionsName ?? getCustomComponentOptionsName(className), + scope ); - if ( - !!scope.annotations.customdialog || - (scope.isDecl && scope.name === CustomComponentNames.BASE_CUSTOM_DIALOG_NAME) - ) { + const updateMembers: arkts.AstNode[] = collect(translatedMembers, body); + const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass(definition, updateMembers); + if (scope.isDecl && scope.name === CustomComponentNames.BASE_CUSTOM_DIALOG_NAME) { updateClassDef.addProperties(factory.addControllerSetMethod(scope.isDecl, body)); } - return arkts.factory.updateClassDeclaration(node, updateClassDef); + return updateClassDef; } /** @@ -610,8 +669,11 @@ export class factory { if (isDecl) { return [this.createCustomDialogMethod(isDecl)]; } - const dialogControllerProperty: arkts.ClassProperty | undefined = body.find( - (item: arkts.AstNode) => arkts.isClassProperty(item) && getCustomDialogController(item).length > 0 + const dialogControllerProperty: arkts.ClassProperty | undefined = findLastPropertyElement( + body as arkts.AstNode[], + (item: arkts.AstNode) => { + return arkts.isClassProperty(item) && getCustomDialogController(item).length > 0; + } ) as arkts.ClassProperty | undefined; if (!!dialogControllerProperty) { return [this.createCustomDialogMethod(isDecl, getCustomDialogController(dialogControllerProperty))]; @@ -702,7 +764,11 @@ export class factory { } } - static createCustomDialogMethod(isDecl: boolean, controller?: string): arkts.MethodDefinition { + static createCustomDialogMethod( + isDecl: boolean, + controller?: string, + controllerType?: string + ): arkts.MethodDefinition { let block: arkts.BlockStatement | undefined = undefined; if (!!controller) { block = arkts.factory.createBlockStatement(this.createSetControllerElements(controller)); @@ -710,7 +776,7 @@ export class factory { const param: arkts.ETSParameterExpression = arkts.factory.createETSParameterExpression( arkts.factory.createIdentifier( CustomDialogNames.CONTROLLER, - UIFactory.createTypeReferenceFromString(CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) + UIFactory.createTypeReferenceFromString(controllerType ?? CustomDialogNames.CUSTOM_DIALOG_CONTROLLER) ), false, undefined @@ -848,7 +914,10 @@ export class factory { return factory.tranformCustomComponentInterfaceMembers(node); } let attributeName: string | undefined; - if (ComponentAttributeCache.getInstance().isCollected() && !!(attributeName = findComponentAttributeInInterface(node))) { + if ( + ComponentAttributeCache.getInstance().isCollected() && + !!(attributeName = findComponentAttributeInInterface(node)) + ) { const componentName = attributeName.replace(/Attribute$/, ''); if (!ComponentAttributeCache.getInstance().hasComponentName(componentName)) { return newNode; @@ -856,7 +925,6 @@ export class factory { const namedOverloads = (projectConfig?.uiPluginOptions as UIPluginOptions)?.namedOverloads ?? false return BuilderLambdaFactory.addDeclaredSetMethodsInAttributeInterface(newNode, componentName, namedOverloads); } - return newNode; } @@ -1024,7 +1092,7 @@ export class factory { getters: getters, }; const body: readonly arkts.AstNode[] = definition.body; - const translators: (ObservedTranslator | MethodTranslator)[] = filterDefined( + const translators: (BaseObservedPropertyTranslator | BaseMethodTranslator)[] = filterDefined( body.map((it) => classifyInObservedClass(it, classScopeInfo)) ); const metaProperty: arkts.ClassProperty[] = ObservedAnno.classHasTrack @@ -1174,6 +1242,7 @@ export class factory { return this.transformResource(node, projectConfig, resourceInfo); } if (isInteropComponent(node)) { + insertInteropComponentImports(); return generateArkUICompatible(node as arkts.CallExpression, globalBuilder); } return node; @@ -1197,14 +1266,13 @@ export class factory { const builder: arkts.Property = properties.at(builderIndex)!; const gensymName: string = GenSymGenerator.getInstance().id(); const newBuilderValue = this.createDialogBuilderArrow(builder.value!, gensymName); - const newProperty = arkts.factory.updateProperty( - builder, builder.kind, builder.key, newBuilderValue, builder.isMethod, builder.isComputed - ); + builder.setValue(newBuilderValue); + CustomDialogControllerBuilderCache.getInstance().updateAll().reset(); const newObj = arkts.factory.updateObjectExpression( options, [ ...(options.properties as arkts.Property[]).slice(0, builderIndex), - newProperty, + builder, ...(options.properties as arkts.Property[]).slice(builderIndex + 1), this.createBaseComponent(), ] @@ -1213,35 +1281,36 @@ export class factory { ? arkts.factory.updateTSAsExpression(optionArg, newObj, optionArg.typeAnnotation, optionArg.isConst) : newObj; const typeRef = node.typeRef as arkts.ETSTypeReference; - const newNode = arkts.factory.updateETSNewClassInstanceExpression(node, typeRef, [newOptions]); - return factory.createBlockStatementForOptionalExpression(newNode, gensymName); + const controller = arkts.factory.updateETSNewClassInstanceExpression(node, typeRef, [newOptions]); + CustomDialogControllerCache.getInstance().collect({ controller }); + return factory.createBlockStatementForOptionalExpression(controller, gensymName); } static createDialogBuilderArrow(value: arkts.Expression, gensymName: string): arkts.Expression { - if ( + let arrowFunc: arkts.ArrowFunctionExpression | undefined; + let call: arkts.CallExpression | undefined; + if (arkts.isArrowFunctionExpression(value)) { + arrowFunc = value; + } else if ( arkts.isCallExpression(value) && arkts.isMemberExpression(value.callee) && arkts.isIdentifier(value.callee.property) && value.callee.property.name === BuilderLambdaNames.TRANSFORM_METHOD_NAME ) { - return addMemoAnnotation( - arkts.factory.createArrowFunctionExpression( - UIFactory.createScriptFunction({ - body: arkts.factory.createBlockStatement([ - arkts.factory.createExpressionStatement( - this.transformCustomDialogComponentCall(value, gensymName) - ), - ]), - flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, - }) - ) + call = this.transformCustomDialogComponentCall(value, gensymName); + arrowFunc = arkts.factory.createArrowFunctionExpression( + UIFactory.createScriptFunction({ + body: arkts.factory.createBlockStatement([arkts.factory.createExpressionStatement(call)]), + flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, + modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + }) ); } - if (arkts.isArrowFunctionExpression(value)) { - return addMemoAnnotation(value); + if (!arrowFunc) { + return value; } - return value; + CustomDialogControllerBuilderCache.getInstance().collect({ arrowFunc, call }); + return addMemoAnnotation(arrowFunc); } static transformCustomDialogComponentCall(value: arkts.CallExpression, gensymName: string): arkts.CallExpression { diff --git a/ui2abc/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts b/ui2abc/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts index 7e708ec7195c9b0508a7255d2ebf4de632eecbe1..13ab2a2d78acb0c62a403e224a6d71a9789e5b60 100644 --- a/ui2abc/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts +++ b/ui2abc/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts @@ -15,14 +15,13 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; -import { ProjectConfig } from '../../common/plugin-context'; +import { ProjectConfig, ResourceInfo } from '../../common/plugin-context'; import { collectCustomComponentScopeInfo, CustomComponentNames, isCustomComponentClass } from '../utils'; import { CustomComponentScopeInfo, isResourceNode, ScopeInfoCollection, LoaderJson, - ResourceInfo, loadBuildJson, initResourceInfo, } from './utils'; diff --git a/ui2abc/arkui-plugins/ui-plugins/struct-translators/utils.ts b/ui2abc/arkui-plugins/ui-plugins/struct-translators/utils.ts index 70cc41b6abb1bbe6c2ffcdf2570f07472ff7867e..51d53ee142545c9e53e60f10a8ff444283bd3ec1 100644 --- a/ui2abc/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -16,7 +16,10 @@ import * as fs from 'fs'; import * as path from 'path'; import * as arkts from '@koalaui/libarkts'; -import { CustomComponentInfo, CustomComponentNames, CustomDialogNames, isKnownMethodDefinition } from '../utils'; +import { + CustomComponentDeclInfo, CustomComponentNames, CustomDialogNames, + InvalidStructInfo, isKnownMethodDefinition, StructInfo +} from '../utils'; import { matchPrefix } from '../../common/arkts-utils'; import { ARKUI_IMPORT_PREFIX_NAMES, @@ -25,35 +28,32 @@ import { DefaultConfiguration, LogType, RESOURCE_TYPE, - InnerComponentNames, - ARKUI_FOREACH_SOURCE_NAME, DecoratorNames, } from '../../common/predefines'; import { DeclarationCollector } from '../../common/declaration-collector'; -import { ProjectConfig } from '../../common/plugin-context'; +import { ProjectConfig, ResourceInfo, ResourceList, ResourceMap } from '../../common/plugin-context'; import { LogCollector } from '../../common/log-collector'; -import { hasDecorator } from '../../ui-plugins/property-translators/utils'; +import { hasDecorator } from '../property-translators/utils'; export type ScopeInfoCollection = { customComponents: CustomComponentScopeInfo[]; }; -export type CustomComponentScopeInfo = CustomComponentInfo & { +interface BaseCustomComponentScopeInfo { hasInitializeStruct?: boolean; hasUpdateStruct?: boolean; hasReusableRebind?: boolean; -}; +} -type ResourceMap = Map>; +export interface StructScopeInfo extends StructInfo, BaseCustomComponentScopeInfo {} -export interface ResourceList { - [key: string]: ResourceMap; -} +export interface StructScopeInfo extends StructInfo, BaseCustomComponentScopeInfo {} -export interface ResourceInfo { - resourcesList: ResourceList; - rawfile: Set; -} +export interface InvalidStructScopeInfo extends InvalidStructInfo, BaseCustomComponentScopeInfo {} + +export interface CustomComponentDeclScopeInfo extends CustomComponentDeclInfo, BaseCustomComponentScopeInfo {} + +export type CustomComponentScopeInfo = StructScopeInfo | InvalidStructScopeInfo | CustomComponentDeclScopeInfo; export interface LoaderJson { hspResourcesMap: Record; @@ -108,11 +108,11 @@ export function isResourceNode(node: arkts.CallExpression, ignoreDecl: boolean = return false; } if (!ignoreDecl) { - const decl = arkts.getDecl(node.callee!); + const decl = arkts.getPeerIdentifierDecl(node.callee.peer); 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; } @@ -334,7 +334,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', @@ -370,7 +370,7 @@ export function preCheckResourceData( } if (!!code && !!message) { LogCollector.getInstance().collectLogInfo({ - type: LogType.ERROR, + level: LogType.ERROR, node: resourceNode, message: message, code: code, @@ -445,7 +445,7 @@ function resourceCheck( } if (!!code && !!message) { LogCollector.getInstance().collectLogInfo({ - type: logType, + level: logType, node: resourceNode, message: message, code: code, @@ -470,8 +470,8 @@ export function generateResourceBundleName(projectConfig: ProjectConfig, isDynam return projectConfig.moduleType === ModuleType.HAR ? DefaultConfiguration.HAR_DEFAULT_BUNDLE_NAME : projectConfig.bundleName - ? projectConfig.bundleName - : ''; + ? projectConfig.bundleName + : ''; } /** @@ -495,8 +495,8 @@ export function generateResourceModuleName( return projectConfig.moduleType === ModuleType.HAR ? DefaultConfiguration.HAR_DEFAULT_MODULE_NAME : projectConfig.moduleName - ? projectConfig.moduleName - : ''; + ? projectConfig.moduleName + : ''; } /** diff --git a/ui2abc/arkui-plugins/ui-plugins/ui-factory.ts b/ui2abc/arkui-plugins/ui-plugins/ui-factory.ts index 28d9a295efa4d9062d98f6a6396a6a67158f2004..5afc13f621da079e8f5fdfd0ecb0e8960cde7549 100644 --- a/ui2abc/arkui-plugins/ui-plugins/ui-factory.ts +++ b/ui2abc/arkui-plugins/ui-plugins/ui-factory.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { BuilderLambdaNames, - CustomComponentAnontations, + CustomComponentAnnotations, CustomComponentNames, CustomDialogNames, hasNullOrUndefinedType, @@ -24,7 +24,8 @@ import { optionsHasField, } from './utils'; import { PartialExcept, PartialNested, PartialNestedExcept } from '../common/safe-types'; -import { ArkTsDefaultNames, DecoratorNames } from '../common/predefines'; +import { BuiltInNames, DecoratorNames } from '../common/predefines'; +import { GenSymGenerator } from '../common/gensym-generator'; import { needDefiniteOrOptionalModifier } from './property-translators/utils'; import { addMemoAnnotation } from '../collectors/memo-collectors/utils'; @@ -134,9 +135,9 @@ export class factory { /** * create `@memo() content: (() => void) | undefined` as parameter */ - static createContentParameter(isOptional: boolean = false): arkts.ETSParameterExpression { + static createContentParameter(): arkts.ETSParameterExpression { const contentParam: arkts.Identifier = factory.createContentIdentifier(); - const param: arkts.ETSParameterExpression = arkts.factory.createETSParameterExpression(contentParam, isOptional, undefined); + const param: arkts.ETSParameterExpression = arkts.factory.createETSParameterExpression(contentParam, false, undefined); addMemoAnnotation(param); return param; } @@ -160,7 +161,10 @@ export class factory { /** * create complex type from string and type parameter, e.g. `Set` */ - static createComplexTypeFromStringAndTypeParameter(name: string, params: readonly arkts.TypeNode[]): arkts.TypeNode { + static createComplexTypeFromStringAndTypeParameter( + name: string, + params: readonly arkts.TypeNode[] + ): arkts.TypeNode { return arkts.factory.createETSTypeReference( arkts.factory.createETSTypeReferencePart( arkts.factory.createIdentifier(name), @@ -195,18 +199,6 @@ export class factory { ); } - /** - * create `throw new Error();` statement - */ - static createThrowStatement(message?: string): arkts.ThrowStatement { - return arkts.factory.createThrowStatement( - arkts.factory.createETSNewClassInstanceExpression( - factory.createTypeReferenceFromString("Error"), - message ? [arkts.factory.createStringLiteral(message)] : [] - ) - ) - } - /** * update ScriptFunction with configurations. */ @@ -291,6 +283,7 @@ export class factory { /** * create intrinsic `@Retention({policy:"SOURCE"})` AnnotationDeclaration with configurations. + * @deprecated */ static createIntrinsicAnnotationDeclaration( config: PartialExcept @@ -387,7 +380,7 @@ export class factory { * * @param method method definition node */ - static generateImplementsForStruct(annotations: CustomComponentAnontations): arkts.TSClassImplements[] { + static generateImplementsForStruct(annotations: CustomComponentAnnotations): arkts.TSClassImplements[] { const implementsInfo: arkts.TSClassImplements[] = []; if (annotations.entry) { implementsInfo.push(factory.createClassImplements(CustomComponentNames.PAGE_LIFE_CYCLE)); @@ -477,9 +470,9 @@ export class factory { static createClassStaticBlock(): arkts.ClassStaticBlock { return arkts.factory.createClassStaticBlock( arkts.factory.createFunctionExpression( - arkts.factory.createIdentifier(ArkTsDefaultNames.DEFAULT_STATIC_BLOCK_NAME), + arkts.factory.createIdentifier(BuiltInNames.DEFAULT_STATIC_BLOCK_NAME), factory.createScriptFunction({ - key: arkts.factory.createIdentifier(ArkTsDefaultNames.DEFAULT_STATIC_BLOCK_NAME), + key: arkts.factory.createIdentifier(BuiltInNames.DEFAULT_STATIC_BLOCK_NAME), body: arkts.factory.createBlockStatement([]), modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, flags: @@ -526,4 +519,63 @@ export class factory { } return this.createTypeReferenceFromString(typeName); } + + /** + * create `?.()` or `{let _tmp = ; _tmp == null ? undefined : _tmp()}` from given `isLowered` flag. + */ + static createOptionalCall( + callee: arkts.Expression, + typeArgs: readonly arkts.TypeNode[], + args: readonly arkts.Expression[], + isLowered?: boolean + ): arkts.Expression { + const typeParams = arkts.factory.createTSTypeParameterInstantiation(typeArgs) + if (!isLowered) { + return arkts.factory.createCallExpression(callee, args, typeParams, true, false); + } + const id = GenSymGenerator.getInstance().id(); + const alternate = arkts.factory.createCallExpression(arkts.factory.createIdentifier(id), args, typeParams, false, false); + const statements: arkts.Statement[] = [ + factory.generateLetVariableDecl(arkts.factory.createIdentifier(id), callee), + factory.generateTernaryExpression(id, alternate), + ]; + return arkts.factory.createBlockExpression(statements); + } + + /** + * generate a variable declaration, e.g. `let = `; + * + * @param left left expression. + * @param right right expression. + */ + static generateLetVariableDecl(left: arkts.Identifier, right: arkts.Expression): arkts.VariableDeclaration { + return arkts.factory.createVariableDeclaration( + arkts.Es2pandaVariableDeclarationKind.VARIABLE_DECLARATION_KIND_LET, + [ + arkts.factory.createVariableDeclarator( + arkts.Es2pandaVariableDeclaratorFlag.VARIABLE_DECLARATOR_FLAG_LET, + left, + right + ), + ] + ); + } + + /** + * generate a ternary expression, e.g. ` ? undefined : `; + * + * @param testLeft the left hand of the test condition. + * @param alternate the alternate of the ternary expression + */ + static generateTernaryExpression(testLeft: string, alternate: arkts.Expression): arkts.ExpressionStatement { + const test = arkts.factory.createBinaryExpression( + arkts.factory.createIdentifier(testLeft), + arkts.factory.createNullLiteral(), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_EQUAL + ); + const consequent: arkts.Expression = arkts.factory.createUndefinedLiteral(); + return arkts.factory.createExpressionStatement( + arkts.factory.createConditionalExpression(test, consequent, alternate) + ); + } } diff --git a/ui2abc/arkui-plugins/ui-plugins/utils.ts b/ui2abc/arkui-plugins/ui-plugins/utils.ts index 2b52f13599ae7e7aec3e337006f4554a28f53fec..1528c4572b46dbf86304fa6a5e19542a6b2eac33 100644 --- a/ui2abc/arkui-plugins/ui-plugins/utils.ts +++ b/ui2abc/arkui-plugins/ui-plugins/utils.ts @@ -19,7 +19,6 @@ import { ARKUI_IMPORT_PREFIX_NAMES, CUSTOM_DIALOG_CONTROLLER_SOURCE_NAME, DecoratorNames, - Dollars, StructDecoratorNames, } from '../common/predefines'; import { DeclarationCollector } from '../common/declaration-collector'; @@ -37,9 +36,9 @@ export enum CustomComponentNames { COMPONENT_INITIALIZERS_NAME = 'initializers', BUILDCOMPATIBLENODE = '_buildCompatibleNode', OPTIONS = 'options', - FACTORY = 'factory', PAGE_LIFE_CYCLE = 'PageLifeCycle', LAYOUT_CALLBACKS = 'LayoutCallbacks', + FACTORY = 'factory', } export enum CustomDialogNames { @@ -151,13 +150,41 @@ export function hasPropertyInAnnotation(annotation: arkts.AnnotationUsage, prope } // CUSTOM COMPONENT -export type CustomComponentInfo = { - name: string; - isDecl: boolean; - annotations: CustomComponentAnontations; -}; +export enum StructType { + STRUCT, + INVALID_STRUCT, + CUSTOM_COMPONENT_DECL, +} + +interface BaseStructInfo { + type: StructType; + name: string; + isDecl: boolean; +} + +export interface StructInfo extends BaseStructInfo { + type: StructType.STRUCT; + annotations: CustomComponentAnnotations; +} + +export interface InvalidStructInfo extends BaseStructInfo { + type: StructType.INVALID_STRUCT; + // No annotations field for invalid structs +} + +export interface CustomComponentDeclInfo extends BaseStructInfo { + type: StructType.CUSTOM_COMPONENT_DECL; +} -export type CustomComponentAnontations = { +export type CustomComponentInfo = StructInfo | InvalidStructInfo | CustomComponentDeclInfo; + +export type EntryInfo = { + className: string; + annotation: arkts.AnnotationUsage; + definition: arkts.ClassDefinition; +} + +export type CustomComponentAnnotations = { component?: arkts.AnnotationUsage; componentV2?: arkts.AnnotationUsage; entry?: arkts.AnnotationUsage; @@ -198,11 +225,11 @@ export function isCustomComponentAnnotation( return false; } if (!ignoreDecl) { - const decl = arkts.getDecl(anno.expr); + const decl = arkts.getPeerIdentifierDecl(anno.expr.peer); 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; } @@ -222,15 +249,16 @@ export function collectCustomComponentScopeInfo( const isDecl: boolean = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); const isCustomComponentClassDecl = !isStruct && isDecl; const shouldIgnoreDecl = isStruct || isDecl; + const name: string = definition.ident.name; if ( isCustomComponentClassDecl && - definition.ident.name !== CustomComponentNames.COMPONENT_CLASS_NAME && - definition.ident.name !== CustomComponentNames.COMPONENT_V2_CLASS_NAME && - definition.ident.name !== CustomComponentNames.BASE_CUSTOM_DIALOG_NAME + name !== CustomComponentNames.COMPONENT_CLASS_NAME && + name !== CustomComponentNames.COMPONENT_V2_CLASS_NAME && + name !== CustomComponentNames.BASE_CUSTOM_DIALOG_NAME ) { return undefined; } - let annotations: CustomComponentAnontations = {}; + let annotations: CustomComponentAnnotations = {}; if (!isCustomComponentClassDecl) { let isCustomComponent: boolean = false; for (const anno of definition.annotations) { @@ -249,14 +277,20 @@ export function collectCustomComponentScopeInfo( }; } if (!isCustomComponent) { - return undefined; + return { type: StructType.INVALID_STRUCT, name, isDecl }; } - } + return { + type: StructType.STRUCT, + name, + isDecl, + annotations: annotations as CustomComponentAnnotations, + }; + } return { - name: definition.ident.name, + type: StructType.CUSTOM_COMPONENT_DECL, + name, isDecl, - annotations: annotations as CustomComponentAnontations, - }; + } } export function getAnnotationInfoForStruct( @@ -354,7 +388,7 @@ export function isCustomDialogControllerOptions( ); } -export function getComponentExtendsName(annotations: CustomComponentAnontations, componentType: ComponentType): string { +export function getComponentExtendsName(annotations: CustomComponentAnnotations, componentType: ComponentType): string { if (!!annotations.customLayout) { componentType.hasCustomLayout ||= true; } diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/index.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/index.ts index 04146828a8166a169a3031526f3e50b312d13e41..dc20af7c441d6c782b9a8719a0cc78f6c9cbe5d3 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/index.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/index.ts @@ -14,98 +14,135 @@ */ import * as arkts from '@koalaui/libarkts'; -import { PluginContext, PluginHandler, Plugins } from '../common/plugin-context'; +import { PluginContext, Plugins } from '../common/plugin-context'; import { - CheckedUISyntaxLinterTransformer, ParsedUISyntaxLinterTransformer, } from './transformers/ui-syntax-linter-transformer'; -import { createUISyntaxRuleProcessor, UISyntaxRuleProcessor } from './processor'; +import { createUISyntaxRuleProcessor } from './processor'; 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 { getConsistentResourceMap, getMainPages, getUIComponents } from '../common/arkts-utils'; +import { Debugger, debugLog } from '../common/debug'; +import { Collector } from '../collectors/collector'; +import { ProgramVisitor } from '../common/program-visitor'; +import { EXTERNAL_SOURCE_PREFIX_NAMES, NodeCacheNames } from '../common/predefines'; +import { MetaDataCollector } from '../common/metadata-collector'; +import { ProgramSkipper } from '../common/program-skipper'; +import { NodeCacheFactory } from '../common/node-cache'; + export function uiSyntaxLinterTransform(): Plugins { - 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), + parsed: parsedTransform, + checked: collectAndLint, + clean(): void { + ProgramSkipper.clear(); + NodeCacheFactory.getInstance().clear(); + }, }; } -export function init(): Plugins { - return uiSyntaxLinterTransform() +function collectAndLint(this: PluginContext): arkts.ETSModule | undefined { + let script: arkts.ETSModule | undefined; + Debugger.getInstance().phasesDebugLog('[UI LINTER PLUGIN] AFTER CHECKED ENTER'); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + const isCoding = this.isCoding?.() ?? false; + if (!isCoding && !!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr, true).program; + script = program.ast as arkts.ETSModule; + debugLog('[BEFORE LINTER SCRIPT] script: ', script); + arkts.Performance.getInstance().createEvent('ui-linter'); + program = checkedProgramVisit(program, this, isCoding); + script = program.ast as arkts.ETSModule; + arkts.Performance.getInstance().stopEvent('ui-linter', true); + debugLog('[AFTER LINTER SCRIPT] script: ', script); + this.setArkTSAst(script); + arkts.Performance.getInstance().logDetailedEventInfos(true); + Debugger.getInstance().phasesDebugLog('[UI LINTER PLUGIN] AFTER CHECKED EXIT'); + return script; + } + Debugger.getInstance().phasesDebugLog('[UI LINTER PLUGIN] AFTER CHECKED EXIT WITH NO TRANSFORM'); + return script; } -function createTransformer( - phase: string, - processor: UISyntaxRuleProcessor, - transformer: UISyntaxLinterVisitor -): PluginHandler { - const visitedPrograms: Set = new Set(); - const visitedExternalSources: Set = new Set(); - return tracePerformance(`UISyntaxPlugin::${phase}`, function (this: PluginContext): arkts.ETSModule | undefined { - const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; - if (!contextPtr) { - return undefined; - } - const projectConfig = this.getProjectConfig(); - if (!projectConfig) { - return undefined; - } - processor.setProjectConfig(projectConfig); - if (projectConfig.frameworkMode) { - return undefined; - } - const program = arkts.getOrUpdateGlobalContext(contextPtr).program; - if (visitedPrograms.has(program.peer) || isHeaderFile(program.absoluteName)) { - return undefined; - } - const isCoding = this.isCoding?.() ?? false; - if (isCoding) { - const codingFilePath = this.getCodingFilePath(); - if (program.absoluteName === codingFilePath) { - return transformProgram.call(this, transformer, program); - } - } else { - transformExternalSources.call(this, program, visitedExternalSources, visitedPrograms, transformer); - if (program.absoluteName) { - return transformProgram.call(this, transformer, program); - } - } - visitedPrograms.add(program.peer); - return undefined; +function checkedProgramVisit( + program: arkts.Program, + context: PluginContext, + isCoding: boolean = false +): arkts.Program { + if (isCoding) { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).shouldCollect(false); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldCollect(false); + } else { + NodeCacheFactory.getInstance().getCache(NodeCacheNames.UI).shouldCollectUpdate(true); + NodeCacheFactory.getInstance().getCache(NodeCacheNames.MEMO).shouldCollectUpdate(true); + } + const projectConfig = context.getProjectConfig(); + arkts.Performance.getInstance().createDetailedEvent('[UI LINTER PLUGIN] MetadataCollector init'); + MetaDataCollector.getInstance() + .setProjectConfig(projectConfig) + .setComponentsInfo(getUIComponents()) + .setConsistentResourceMap(getConsistentResourceMap()) + .setMainPages(getMainPages(projectConfig)); + arkts.Performance.getInstance().stopDetailedEvent('[UI LINTER PLUGIN] MetadataCollector init'); + const collector = new Collector({ + shouldCollectUI: true, + shouldCollectMemo: true, + shouldCheckUISyntax: true + }); + const programVisitor = new ProgramVisitor({ + pluginName: uiSyntaxLinterTransform.name, + state: arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + visitors: [collector], + skipPrefixNames: EXTERNAL_SOURCE_PREFIX_NAMES, + pluginContext: context, }); + program = programVisitor.programVisitor(program); + MetaDataCollector.getInstance() + .setComponentsInfo(undefined) + .setConsistentResourceMap(undefined) + .setMainPages(undefined); + if (!isCoding) { + NodeCacheFactory.getInstance().perfLog(NodeCacheNames.UI, true); + NodeCacheFactory.getInstance().perfLog(NodeCacheNames.MEMO, true); + } + return program; } -function transformExternalSources( - this: PluginContext, - program: arkts.Program, - visitedExternalSources: Set, - visitedPrograms: Set, - transformer: UISyntaxLinterVisitor -): void { - const externalSources = program.getExternalSources(); - for (const externalSource of externalSources) { - if (matchPrefix(EXCLUDE_EXTERNAL_SOURCE_PREFIXES, externalSource.getName())) { - continue; - } - if (visitedExternalSources.has(externalSource)) { - continue; - } - const programs = externalSource.programs; - for (const program of programs) { - if (visitedPrograms.has(program.peer) || isHeaderFile(program.absoluteName)) { - continue; - } - const script = transformer.transform(program.ast) as arkts.ETSModule; - this.setArkTSAst(script); - } - visitedExternalSources.add(externalSource.peer); + +const visitedPrograms: Set = new Set(); +function parsedTransform(this: PluginContext): arkts.ETSModule | undefined { + const isCoding = this.isCoding?.() ?? false; + if (!isCoding) { + return undefined; } + arkts.Performance.getInstance().createEvent(`ui-syntax::parsed`); + const processor = createUISyntaxRuleProcessor(rules); + const transformer = new ParsedUISyntaxLinterTransformer(processor); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!contextPtr) { + return undefined; + } + const projectConfig = this.getProjectConfig(); + if (!projectConfig) { + return undefined; + } + processor.setProjectConfig(projectConfig); + if (projectConfig.frameworkMode) { + return undefined; + } + const program = arkts.getOrUpdateGlobalContext(contextPtr, true).program; + if (visitedPrograms.has(program.peer) || isHeaderFile(program.absoluteName)) { + return undefined; + } + const codingFilePath = this.getCodingFilePath(); + if (program.absoluteName === codingFilePath) { + return transformProgram.call(this, transformer, program); + } + visitedPrograms.add(program.peer); + arkts.Performance.getInstance().stopEvent(`ui-syntax::parsed`, true); + return undefined; } function transformProgram( @@ -121,3 +158,8 @@ function transformProgram( function isHeaderFile(fileName: string): boolean { return fileName.endsWith('.d.ets'); } + +// required for es2panda +export function init(): Plugins { + return uiSyntaxLinterTransform() +} diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/processor/index.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/processor/index.ts index b8927faee6983702ac7aa5eda7b46a1f3b796666..3c5144fa15913b9d66efa9dd173515cde68598f6 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/processor/index.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/processor/index.ts @@ -23,8 +23,8 @@ import { UISyntaxRuleContext, UISyntaxRuleHandler, } from '../rules/ui-syntax-rule'; -import { getUIComponents, readJSON, UISyntaxRuleComponents } from '../utils'; -import { ProjectConfig } from 'common/plugin-context'; +import { ProjectConfig, UIComponents } from '../../common/plugin-context'; +import { getUIComponents } from '../../common/arkts-utils'; export type UISyntaxRuleProcessor = { setProjectConfig(projectConfig: ProjectConfig): void; @@ -48,11 +48,11 @@ const BASE_RESOURCE_PATH = 'src/main/resources/base'; const ETS_PATH = 'src/main/ets'; class ConcreteUISyntaxRuleContext implements UISyntaxRuleContext { - public componentsInfo: UISyntaxRuleComponents | undefined; + public componentsInfo: UIComponents | undefined; public projectConfig?: ProjectConfig; constructor() { - this.componentsInfo = getUIComponents('../../components/'); + this.componentsInfo = getUIComponents(); } public report(options: ReportOptions): void { @@ -91,39 +91,6 @@ class ConcreteUISyntaxRuleContext implements UISyntaxRuleContext { } } - getMainPages(): string[] { - if (!this.projectConfig) { - return []; - } - const { moduleRootPath, aceModuleJsonPath } = this.projectConfig; - if (!aceModuleJsonPath) { - return []; - } - const moduleConfig = readJSON(aceModuleJsonPath); - if (!moduleConfig) { - return []; - } - if (!moduleConfig.module || !moduleConfig.module.pages) { - return []; - } - const pagesPath = moduleConfig.module.pages; - const matcher = /\$(?[_A-Za-z]+):(?[_A-Za-z]+)/.exec(pagesPath); - if (matcher && matcher.groups) { - const { directory, filename } = matcher.groups; - const mainPagesPath = path.resolve(moduleRootPath, BASE_RESOURCE_PATH, directory, `${filename}.json`); - const mainPages = readJSON(mainPagesPath); - if (!mainPages) { - return []; - } - if (!mainPages.src || !Array.isArray(mainPages.src)) { - return []; - } - return mainPages.src.map((page) => path.resolve(moduleRootPath, ETS_PATH, `${page}.ets`)); - } else { - return []; - } - } - private format(content: string, placeholders: object): string { return Object.entries(placeholders).reduce((content, [placehoderName, placehoderValue]) => { // Fixed a bug where $$ was converted to $ diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/component-componentV2-mix-use-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/component-componentV2-mix-use-check.ts index 42284724f1e831f658ed8cbe7043b89cbae6f840..0abcae2aaf65f14b70a940eb3fdb874d9b3a1320 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/component-componentV2-mix-use-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/component-componentV2-mix-use-check.ts @@ -130,7 +130,7 @@ class ComponentComponentV2MixUseCheckRule extends AbstractUISyntaxRule { annotationName: string ): void { if (arkts.isClassProperty(node)) { - this.processNode(node, annotationName); + this.checkClassProperty(node); } for (const child of node.getChildren()) { @@ -138,42 +138,31 @@ class ComponentComponentV2MixUseCheckRule extends AbstractUISyntaxRule { } } - private processNode( - node: arkts.ClassProperty, - annotationName: string + private checkClassProperty( + node: arkts.ClassProperty ): void { - const queue: Array = [node]; - while (queue.length > 0) { - const currentNode: arkts.AstNode = queue.shift() as arkts.AstNode; - if (arkts.isIdentifier(currentNode)) { - const name = getIdentifierName(currentNode); - - if ( - annotationName === PresetDecorators.COMPONENT_V1 && - this.observedV2Names.has(name) - ) { - this.checkObservedConflict(node, v1ComponentDecorators); - break; - } - } - const children = currentNode.getChildren(); - for (const child of children) { - queue.push(child); - } + const typeAnnotation = node.typeAnnotation; + if (!typeAnnotation || !arkts.isETSTypeReference(typeAnnotation)) { + return; + } + + const identifier = typeAnnotation.part?.name; + if (!identifier || !arkts.isIdentifier(identifier)) { + return; + } + + const typeName = identifier.name; + if (!this.observedV2Names.has(typeName)) { + return; } - } - private checkObservedConflict( - node: arkts.ClassProperty, - componentDecorators: string[] - ): void { node.annotations.forEach((anno) => { if (!anno.expr) { return; } const annotationName = getIdentifierName(anno.expr); - if (annotationName && componentDecorators.includes(annotationName)) { + if (annotationName && v1ComponentDecorators.includes(annotationName)) { this.report({ node: anno, message: this.messages.observedv2_v1, diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/componentV2-state-usage-validation.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/componentV2-state-usage-validation.ts index 84d26101b6155cdbe2d74980f330de7ae00124cb..e6450afc2ba06f31537b13de0f93e7f4843c2615 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/componentV2-state-usage-validation.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/componentV2-state-usage-validation.ts @@ -165,11 +165,9 @@ class ComponentV2StateUsageValidationRule extends AbstractUISyntaxRule { } private validateClassPropertyDecorators(node: arkts.ETSStructDeclaration): void { - if (node.definition) { - this.checkuseStateDecoratorsWithProperty(node.definition); - } + this.checkuseStateDecoratorsWithProperty(node.definition); const isComponentV2 = this.hasComponentV2Annotation(node); - node.definition?.body.forEach(member => { + node.definition.body.forEach(member => { if (!arkts.isClassProperty(member)) { return; } diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/computed-decorator-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/computed-decorator-check.ts index 6628ce43de4fdc96fd37f1f3cb682820ccf61d0b..7b22bd4e5f2f6fee0cfda7a3a1e5db63bd79b381 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/computed-decorator-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/computed-decorator-check.ts @@ -23,9 +23,9 @@ class ComputedDecoratorCheckRule extends AbstractUISyntaxRule { public setup(): Record { return { - onlyOnGetter: `@Computed can only decorate 'GetAccessor'.`, + onlyOnGetter: `'@Computed' can only decorate 'GetAccessor'.`, onlyInObservedV2: `The '@Computed' can decorate only member method within a 'class' decorated with ObservedV2.`, - componentV2InStruct: `The '@Computed' annotation can only be used in a 'struct' decorated with ComponentV2.`, + componentV2InStruct: `The '@Computed' annotation can only be used in a 'struct' decorated with '@ComponentV2'.`, noTwoWayBinding: `A property decorated by '@Computed' cannot be used with two-way bind syntax.`, computedMethodDefineSet: `A property decorated by '@Computed' cannot define a set method.` }; @@ -203,8 +203,12 @@ class ComputedDecoratorCheckRule extends AbstractUISyntaxRule { const observedDecorator = getClassAnnotationUsage(node, PresetDecorators.OBSERVED_V1); node.definition?.body.forEach((member) => { - if (arkts.isMethodDefinition(member)) { + if (arkts.isClassProperty(member)) { + this.validateComputedOnClassProperty(member); + return; + } + if (arkts.isMethodDefinition(member)) { this.validateComputedInClass(node, member, observedV2Decorator, observedDecorator); const computedDecorator = findDecorator(member.function!, PresetDecorators.COMPUTED); if (!arkts.isIdentifier(member.id)) { diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/construct-parameter.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/construct-parameter.ts index bff0ab8e9ecc6e5bf977510a363b751461fb33e5..8b75d2cb4e9ef97cb47749c168d9e9c7739da40f 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/construct-parameter.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/construct-parameter.ts @@ -20,7 +20,6 @@ import { getClassPropertyAnnotationNames, PresetDecorators, getAnnotationName, - getMethodDefinitionName, } from '../utils'; import { AbstractUISyntaxRule } from './ui-syntax-rule'; @@ -83,7 +82,7 @@ class ConstructParameterRule extends AbstractUISyntaxRule { if (arkts.isClassProperty(item) && getClassPropertyName(item) === propertyName) { annotationNames = getClassPropertyAnnotationNames(item); } - if (arkts.isMethodDefinition(item) && getMethodDefinitionName(item) === propertyName) { + if (arkts.isMethodDefinition(item) && getIdentifierName(item) === propertyName) { annotationNames = item.function!.annotations.map((annotation) => getAnnotationName(annotation) ); @@ -255,7 +254,16 @@ class ConstructParameterRule extends AbstractUISyntaxRule { }); } } - if (childType === PresetDecorators.BUILDER_PARAM && !isBuilder && !isBuilderInStruct) { + let isBuilderArrow: boolean = false; + if (arkts.isArrowFunctionExpression(property.value)) { + const annotations = property.value.annotations + const found = annotations?.filter(it => { + const name = getAnnotationName(it) + return name == PresetDecorators.BUILDER + }) + isBuilderArrow = (found.length != 0) + } + if (childType === PresetDecorators.BUILDER_PARAM && !isBuilder && !isBuilderInStruct && !isBuilderArrow) { this.report({ node: property, message: this.messages.parameterIsBuilderParam, diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/consumer-provider-decorator-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/consumer-provider-decorator-check.ts index 31463b2959eeeb1f9ba8e902c566eddb76d4b2c0..13f138432da951d21d74a5a3004869e84ba6294d 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/consumer-provider-decorator-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/consumer-provider-decorator-check.ts @@ -175,7 +175,7 @@ class ConsumerProviderDecoratorCheckRule extends AbstractUISyntaxRule { } private validateOnlyInStruct(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && !arkts.isETSStructDeclaration(node)) { + if (arkts.isClassDeclaration(node)) { node.definition?.body.forEach(member => { if (arkts.isClassProperty(member)) { this.validateDecorator(member, this.messages.providerAndConsumerOnlyInStruct, PresetDecorators.CONSUMER); diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/index.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/index.ts index fee6bf307bc0233789b436f918ec6a666091e976..57188378d22864505da750d13077b6957a540824 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/index.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/index.ts @@ -91,14 +91,12 @@ const rules: Array = [ [NestedRelationshipRule, 'error'], [NestedReuseComponentCheckRule, 'error'], [NoChildInButtonRule, 'error'], - [NoDuplicateEntryRule, 'error'], [NoDuplicateIdRule, 'warn'], [NoDuplicatePreviewRule, 'error'], [NoPropLinkObjectLinkInEntryRule, 'warn'], [NoSameAsBuiltInAttributeRule, 'error'], [ReuseAttributeCheckRule, 'error'], [StaticParamRequireRule, 'warn'], - [StructMissingDecoratorRule, 'error'], [StructPropertyDecoratorRule, 'error'], [TrackDecoratorCheckRule, 'error'], [ValidateBuildInStructRule, 'error'], @@ -115,7 +113,6 @@ const rules: Array = [ [ComponentComponentV2InitCheckRule, 'error'], [ReusableV2DecoratorCheckRule, 'error'], [VariableInitializationViaComponentConstructorRule, 'error'], - [StructNoExtendsRule, 'error'], [UiConsistentCheckRule, 'warn'], [ValidateDecoratorTargetRule, 'error'], [WatchDecoratorFunctionRule, 'error'], diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/main-pages-entry-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/main-pages-entry-check.ts index dee25f44d49dc5a0a7750f0b52f981c25294155a..d589cfbe964aff3dce86e8b6bd10e0e8a7a96439 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/main-pages-entry-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/main-pages-entry-check.ts @@ -16,6 +16,8 @@ import * as arkts from '@koalaui/libarkts'; import { getAnnotationUsage, getCurrentFilePath, PresetDecorators } from '../utils'; import { AbstractUISyntaxRule } from './ui-syntax-rule'; +import { getMainPages } from '../../common/arkts-utils'; +import { MetaDataCollector } from '../../common/metadata-collector'; class MainPagesEntryCheckRule extends AbstractUISyntaxRule { public setup(): Record { @@ -28,10 +30,8 @@ class MainPagesEntryCheckRule extends AbstractUISyntaxRule { return; } const currentFilePath = getCurrentFilePath(node); - if (!currentFilePath) { - return; - } - if (!this.context.getMainPages().includes(currentFilePath)) { + const mainPages = getMainPages(this.context.projectConfig); + if (!currentFilePath || !mainPages || !mainPages.includes(currentFilePath)) { return; } let entryDecoratorCount = 0; diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/nested-relationship.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/nested-relationship.ts index 4baa34504fde6b73f64886705483dc4773d5e7c2..2e93e9eeee93cc113024344fc7c3d7eb8a02d84c 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/nested-relationship.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/nested-relationship.ts @@ -131,12 +131,10 @@ class NestedRelationshipRule extends AbstractUISyntaxRule { return; } member.statements.forEach(statement => { - if (!arkts.isExpressionStatement(statement) || !statement.expression || - !arkts.isCallExpression(statement.expression) || !statement.expression.callee || - !arkts.isIdentifier(statement.expression.callee)) { + const childComponentNode = this.findChildComponentNode(statement); + if (!childComponentNode) { return; } - const childComponentNode = statement.expression.callee; const childComponentName = getIdentifierName(childComponentNode); if (childComponentListArray.includes(childComponentName) || !isBuildInComponent(this.context, childComponentName)) { @@ -159,6 +157,28 @@ class NestedRelationshipRule extends AbstractUISyntaxRule { }); } + private findChildComponentNode(stmt: arkts.AstNode): arkts.Identifier | undefined { + if ( + !arkts.isExpressionStatement(stmt) || + !stmt.expression || + !arkts.isCallExpression(stmt.expression) || + !stmt.expression.callee + ) { + return undefined; + } + if (arkts.isIdentifier(stmt.expression.callee)) { + return stmt.expression.callee; + } + if ( + arkts.isMemberExpression(stmt.expression.callee) && + arkts.isCallExpression(stmt.expression.callee.object) && + arkts.isIdentifier(stmt.expression.callee.object.callee) + ) { + return stmt.expression.callee.object.callee; + } + return undefined; + } + private reportDelegateChildrenComponentChildren( parentNode: arkts.Identifier, childComponentName: string, diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/old-new-decorator-mix-use-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/old-new-decorator-mix-use-check.ts index 664a5658b10dbb05b551f66d08ebcc3c0dc85830..25cddd6de0e9730cad75e970e18c9a0e046cdb55 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/old-new-decorator-mix-use-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/old-new-decorator-mix-use-check.ts @@ -18,7 +18,7 @@ import { PresetDecorators, getAnnotationName, getAnnotationUsage, getIdentifierN import { AbstractUISyntaxRule } from './ui-syntax-rule'; class OldNewDecoratorMixUseCheckRule extends AbstractUISyntaxRule { - private static readonly oldV1Decorators: string[] = [ + private oldV1Decorators: string[] = [ PresetDecorators.STATE, PresetDecorators.PROP_REF, PresetDecorators.LINK, @@ -31,7 +31,7 @@ class OldNewDecoratorMixUseCheckRule extends AbstractUISyntaxRule { PresetDecorators.OBJECT_LINK, ]; - private static readonly newV2decorators: string[] = [ + private newV2decorators: string[] = [ PresetDecorators.LOCAL, PresetDecorators.PARAM, PresetDecorators.ONCE, @@ -42,6 +42,11 @@ class OldNewDecoratorMixUseCheckRule extends AbstractUISyntaxRule { PresetDecorators.COMPUTED, ]; + private notAllowedInClass: string[] = [ + PresetDecorators.LOCAL, + PresetDecorators.PARAM, + ]; + public setup(): Record { return { oldAndNewDecoratorsMixUse: `The '@{{decoratorName}}' annotation can only be used in a 'struct' decorated with '@{{component}}'.`, @@ -64,8 +69,8 @@ class OldNewDecoratorMixUseCheckRule extends AbstractUISyntaxRule { if (!arkts.isClassProperty(property)) { return; } - const newDecorator = this.findPropertyDecorator(property, OldNewDecoratorMixUseCheckRule.newV2decorators); - const oldDecorator = this.findPropertyDecorator(property, OldNewDecoratorMixUseCheckRule.oldV1Decorators); + const newDecorator = this.findPropertyDecorator(property, this.newV2decorators); + const oldDecorator = this.findPropertyDecorator(property, this.oldV1Decorators); // Check that the new decorator is used for component v2 if (newDecorator && !componentV2Decorator && componentDecorator) { this.reportErrorAndChangeDecorator(newDecorator, componentDecorator, PresetDecorators.COMPONENT_V2); @@ -85,15 +90,9 @@ class OldNewDecoratorMixUseCheckRule extends AbstractUISyntaxRule { if (!arkts.isClassProperty(property)) { return; } - const newDecorator = this.findPropertyDecorator(property, OldNewDecoratorMixUseCheckRule.newV2decorators); - const oldDecorator = this.findPropertyDecorator(property, OldNewDecoratorMixUseCheckRule.oldV1Decorators); - // Check that the new decorator is not used in struct - if (newDecorator) { - this.reportError(newDecorator, PresetDecorators.COMPONENT_V2); - } - // Check that the old decorator is not used in struct - if (oldDecorator) { - this.reportError(oldDecorator, PresetDecorators.COMPONENT_V1); + const decorator = this.findPropertyDecorator(property, this.notAllowedInClass); + if (decorator) { + this.reportError(decorator, PresetDecorators.COMPONENT_V2); } }); } diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/once-decorator-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/once-decorator-check.ts index aeeb9157fdb13889c7310db87750eefec4e79ad0..a598023da21d5993bd0c91297df01d1df0fe5054 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/once-decorator-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/once-decorator-check.ts @@ -37,7 +37,7 @@ class OnceDecoratorCheckRule extends AbstractUISyntaxRule { } private validateOnlyInStruct(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && !arkts.isETSStructDeclaration(node)) { + if (arkts.isClassDeclaration(node)) { node.definition?.body.forEach(member => { if (arkts.isClassProperty(member)) { this.validateOnceDecoratorUsage(member, this.messages.invalidNOtInStruct); diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-consistent-check.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-consistent-check.ts index 429ffb19b652a619bd61e10200589aba078d4e21..9a5d5854da59acaf02126869af9f9f1e1a3d4bf6 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-consistent-check.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-consistent-check.ts @@ -15,7 +15,7 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractUISyntaxRule } from './ui-syntax-rule'; -import { getConsistentResourceInfo } from '../utils'; +import { getConsistentResourceMap } from '../../common/arkts-utils'; class UiConsistentCheckRule extends AbstractUISyntaxRule { // UI consistency is only detect in the limited decorator @@ -31,7 +31,7 @@ class UiConsistentCheckRule extends AbstractUISyntaxRule { // Resource color type tags private static readonly resourceColorType = 'ResourceColor'; - private static readonly consistentResourceInfo = getConsistentResourceInfo(); + private static readonly consistentResourceInfo = getConsistentResourceMap(); public setup(): Record { return { diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-syntax-rule.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-syntax-rule.ts index a3a20dd64ca511625ecf5d1813b4cbfd98615284..59f957fe70f9f64522b3e1e7b7c1d3a94c2f69ed 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-syntax-rule.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/ui-syntax-rule.ts @@ -14,8 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; -import { ProjectConfig } from 'common/plugin-context'; -import { UISyntaxRuleComponents } from 'ui-syntax-plugins/utils'; +import { ProjectConfig, UIComponents } from '../../common/plugin-context'; export type FixSuggestion = { range: [start: arkts.SourcePosition, end: arkts.SourcePosition]; @@ -33,9 +32,8 @@ export type ReportOptions = { export type UISyntaxRuleContext = { projectConfig?: ProjectConfig; - componentsInfo: UISyntaxRuleComponents | undefined; + componentsInfo: UIComponents | undefined; report(options: ReportOptions): void; - getMainPages(): string[]; }; export type UISyntaxRulePhaseHandler = (node: arkts.AstNode) => void; diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/validate-decorator-target.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/validate-decorator-target.ts index 4bdb2cf784f9b104650c7ad68297a99a2f543490..9f64d00e98aa966ade6b20aa9405a90d8971217f 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/rules/validate-decorator-target.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/rules/validate-decorator-target.ts @@ -72,7 +72,7 @@ class ValidateDecoratorTargetRule extends AbstractUISyntaxRule { private validateDecoratorStructOnly(node: arkts.AstNode): void { // class - if (arkts.isClassDeclaration(node)) { + if (arkts.isClassDeclaration(node) && !arkts.isETSStructDeclaration(node)) { node.definition?.annotations?.forEach((annotation) => { this.validateDecorator(annotation, structOnlyDecorators, this.messages.decoratorOnlyWithStruct); }); diff --git a/ui2abc/arkui-plugins/ui-syntax-plugins/utils/index.ts b/ui2abc/arkui-plugins/ui-syntax-plugins/utils/index.ts index d3bac38e739d4440f24b1d1f3629a40c9c0888a9..b1884c5c6e91ed6930a4fce42aa03992e3d5832e 100644 --- a/ui2abc/arkui-plugins/ui-syntax-plugins/utils/index.ts +++ b/ui2abc/arkui-plugins/ui-syntax-plugins/utils/index.ts @@ -14,9 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; -import * as fs from 'fs'; -import * as path from 'path'; -import { UISyntaxRuleContext } from 'ui-syntax-plugins/rules/ui-syntax-rule'; +import { UISyntaxRuleContext } from '../rules/ui-syntax-rule'; export const EXCLUDE_EXTERNAL_SOURCE_PREFIXES: Array = [ 'std', @@ -281,123 +279,6 @@ export function hasAnnotation(annoArray: readonly arkts.AnnotationUsage[], annot return (annoArray || []).some((anno) => anno.expr && getIdentifierName(anno.expr) === annotationName); } -interface ComponentJson { - name: string; - atomic?: boolean; - attrs: string[]; - single?: boolean; - parents?: string[]; - children?: string[]; -} - -export interface UISyntaxRuleComponents { - builtInAttributes: string[]; - containerComponents: string[]; - atomicComponents: string[]; - singleChildComponents: string[]; - validParentComponent: Map; - validChildComponent: Map; -} - -export function getUIComponents(dirPath: string): UISyntaxRuleComponents | undefined { - const absolutePath = path.resolve(__dirname, dirPath); - let builtInAttributes: string[] = []; - let containerComponents: string[] = []; - let atomicComponents: string[] = []; - let singleChildComponents: string[] = []; - let validParentComponent: Map = new Map(); - let validChildComponent: Map = new Map(); - - if (!fs.existsSync(absolutePath)) { - return undefined; - } - // Read all files in the directory - const files = fs.readdirSync(absolutePath); - - files.forEach((file) => { - if (path.extname(file) === '.json') { - const filePath = path.join(absolutePath, file); - const fileContent = fs.readFileSync(filePath, 'utf-8'); - const componentJson: ComponentJson = JSON.parse(fileContent); - // Record the container component name - if ((!componentJson.atomic || componentJson.atomic !== true) && componentJson.name) { - containerComponents.push(componentJson.name); - } - // Record the atomic component name - if (componentJson.atomic && componentJson.atomic === true && componentJson.name) { - atomicComponents.push(componentJson.name); - } - // Record the name of a single subcomponent component name - if (componentJson.single && componentJson.single === true && componentJson.name) { - singleChildComponents.push(componentJson.name); - } - // Record a valid parent component name - if (componentJson.parents && componentJson.name) { - validParentComponent.set(componentJson.name, componentJson.parents); - } - // Record a valid children component name - if (componentJson.children && componentJson.name) { - validChildComponent.set(componentJson.name, componentJson.children); - } - // Document all built-in attributes - componentJson.attrs - ?.filter((attr) => !builtInAttributes.includes(attr)) - .forEach((attr) => builtInAttributes.push(attr)); - } - }); - const componentsInfo: UISyntaxRuleComponents = { - builtInAttributes, - containerComponents, - atomicComponents, - singleChildComponents, - validParentComponent, - validChildComponent, - }; - - return componentsInfo; -} - -export function getConsistentResourceInfo(): Map { - const resultMap = new Map(); - const consistentResourcePath = - path.resolve(__dirname, '../../../../../../../previewer/common/resources/entry/resources.txt'); - let resourceText: string = ''; - try { - // The contents of the file are read synchronously - resourceText = fs.readFileSync(path.resolve(consistentResourcePath), 'utf-8'); - } catch (error: unknown) { - return resultMap; - } - // Split text by line - const lines = resourceText.split('\n'); - for (const line of lines) { - // Skip blank lines - if (!line.trim()) { - continue; - } - const match = line.match(/id:(\d+),\s*'([^']+)'\s*'([^']+)'/); - if (match && match.length === 4) { - const id = match[1]; - const value = match[2]; - const resourceName = match[3]; - // Remove resource names that start with 'ohos_id' or 'ohos_fa' - if (resourceName.startsWith('ohos_id') || resourceName.startsWith('ohos_fa')) { - continue; - } - let entries = resultMap.get(value); - if (!entries) { - entries = []; - resultMap.set(value, entries); - } - entries.push({ - id: id, - resourceName: resourceName, - }); - } - } - return resultMap; -} - export function isBuiltInAttribute(context: UISyntaxRuleContext, attributeName: string): boolean { if (!context.componentsInfo) { return false; @@ -435,17 +316,6 @@ export function isSingleChildComponent(context: UISyntaxRuleContext, componentNa return context.componentsInfo.singleChildComponents.includes(componentName); } -export function readJSON(path: string): T | null { - if (!fs.existsSync(path)) { - return null; - } - const content = fs.readFileSync(path).toString(); - if (!content) { - return null; - } - return JSON.parse(content) as T; -} - export function tracePerformance any>(name: string, fn: T): T { return function (this: ThisParameterType, ...args: Parameters): ReturnType { arkts.Performance.getInstance().createEvent(name); @@ -486,7 +356,7 @@ export function getAnnotationUsageByName( return false; } const program = arkts.getProgramFromAstNode(annotationDeclaration); - if (!isFromPresetModules(program.moduleName)) { + if (!program || !isFromPresetModules(program.moduleName)) { return false; } return true; @@ -554,11 +424,4 @@ export const TypeFlags = { export function getCurrentFilePath(node: arkts.AstNode): string | undefined { const program = arkts.getProgramFromAstNode(node); return program.absoluteName; -} - -export function getMethodDefinitionName(property: arkts.MethodDefinition): string | undefined { - if (!property.key) { - return undefined; - } - return getIdentifierName(property.key); } \ No newline at end of file diff --git a/ui2abc/ets-tests/ets/environment-tests/pages/monitor/MonitorDecorator.ets b/ui2abc/ets-tests/ets/environment-tests/pages/monitor/MonitorDecorator.ets index f2a2e66ddf6fef57058bc8ac75bff578e94015cf..48c620b3ec45cb87db985eb88d3c31da1ab54d78 100644 --- a/ui2abc/ets-tests/ets/environment-tests/pages/monitor/MonitorDecorator.ets +++ b/ui2abc/ets-tests/ets/environment-tests/pages/monitor/MonitorDecorator.ets @@ -86,7 +86,7 @@ struct MonitorDecorator { }) } - infoClass: Info = new Info(); + infoClass: Info = new Info(""); @Monitor(["infoClass.message"]) onInfoChange(monitor: IMonitor) { monitor.dirty.forEach((path: string) => {