From 57c13928dc0922686179e44ddab653118badfc5b Mon Sep 17 00:00:00 2001 From: Jiakai Shi Date: Wed, 9 Apr 2025 23:32:38 +0800 Subject: [PATCH 1/3] support arkts cache Signed-off-by: Jiakai Shi Change-Id: I115ef6cbf60ef970bb2eb17caf988af865954209 --- arkui-plugins/common/arkts-utils.ts | 18 - .../declaration-collector.ts} | 36 +- arkui-plugins/common/plugin-context.ts | 13 + arkui-plugins/common/predefines.ts | 87 ++- arkui-plugins/common/program-visitor.ts | 142 +++-- .../safe-types.ts} | 72 +-- arkui-plugins/interop-plugins/index.ts | 1 - .../memo-plugins/function-transformer.ts | 44 +- arkui-plugins/memo-plugins/index.ts | 15 +- arkui-plugins/memo-plugins/memo-factory.ts | 1 - .../memo-plugins/parameter-transformer.ts | 45 +- .../memo-plugins/signature-transformer.ts | 5 + arkui-plugins/memo-plugins/utils.ts | 43 +- arkui-plugins/package.json | 3 +- .../demo/localtest/build_config_template.json | 7 +- .../test/demo/localtest/entry/new.ets | 74 +-- .../mock/builder-lambda/simple-component.ets | 2 +- .../mock/common-utils/annotation.ets} | 20 +- .../mock/memo/functions/argument-call.ets | 2 +- .../mock/memo/functions/declare-and-call.ets | 2 +- .../mock/memo/functions/inner-functions.ets | 2 +- .../memo/functions/non-void-return-type.ets | 2 +- .../mock/memo/functions/type-reference.ets | 2 +- .../mock/memo/functions/void-return-type.ets | 2 +- .../demo/mock/memo/lambdas/argument-call.ets | 2 +- .../mock/memo/lambdas/trailing-lambdas.ets | 2 +- .../demo/mock/memo/lambdas/void-lambda.ets | 2 +- .../demo/mock/memo/lambdas/with-receiver.ets | 2 +- .../demo/mock/memo/methods/argument-call.ets | 2 +- .../test/demo/mock/memo/methods/callable.ets | 2 +- .../mock/memo/methods/declare-and-call.ets | 2 +- .../demo/mock/memo/methods/void-method.ets | 2 +- .../memo/properties/class-constructor.ets | 2 +- .../mock/memo/properties/class-properties.ets | 2 +- .../demo/mock/memo/properties/implements.ets | 2 +- .../demo/mock/memo/properties/interfaces.ets | 2 +- ...ohos.arkui.component.customComponent.d.ets | 57 -- .../@ohos.arkui.component.styledString.d.ets | 32 -- .../local/@ohos.arkui.component.text.d.ets | 132 ----- .../@ohos.arkui.stateManagement.common.d.ets | 61 -- .../@ohos.arkui.stateManagement.runtime.d.ets | 62 -- .../@ohos.arkui.stateManagement.storage.d.ets | 119 ---- arkui-plugins/test/package.json | 1 + arkui-plugins/test/test.log | 372 ------------ .../test/ut/common/annotation.test.ts | 191 ++++++- .../argument-call.test.ts | 12 +- .../declare-and-call.test.ts | 12 +- .../inner-functions.test.ts | 12 +- .../non-void-return-type.test.ts | 12 +- .../type-reference.test.ts | 12 +- .../void-return-type.test.ts | 12 +- .../lambda-literals/argument-call.test.ts | 12 +- .../lambda-literals/trailing-lambdas.test.ts | 12 +- .../lambda-literals/void-lambda.test.ts | 12 +- .../lambda-literals/with-receiver.test.ts | 12 +- .../method-declarations/argument-call.test.ts | 12 +- .../method-declarations/callable.test.ts | 12 +- .../declare-and-call.test.ts | 12 +- .../internal-calls.test.ts | 10 +- .../non-void-method.test.ts | 16 +- .../method-declarations/void-method.test.ts | 12 +- .../class-constructor.test.ts | 12 +- .../class-properties.test.ts | 12 +- .../property-declarations/interfaces.test.ts | 12 +- .../animation/animation-basic.test.ts | 28 +- .../custom-component-call.test.ts | 24 +- .../builder-lambda/simple-component.test.ts | 12 +- .../builder-param-passing.test.ts | 25 +- .../init-with-local-builder.test.ts | 19 +- .../decorators/builder/global-builder.test.ts | 27 +- .../decorators/builder/local-builder.test.ts | 26 +- .../decorators/link/link-basic-type.test.ts | 2 +- .../decorators/link/link-complex-type.test.ts | 2 +- .../link/link-to-link-prop-state.test.ts | 2 +- .../decorators/link/state-to-link.test.ts | 4 +- .../observed-track/observed-only.test.ts | 37 +- .../observed-track-class-property.test.ts | 35 +- .../observed-track-complex-type.test.ts | 38 +- .../observed-track-extends.test.ts | 37 +- .../observed-track-implements.test.ts | 37 +- .../observed-track/observed-track.test.ts | 37 +- .../observed-track/track-only.test.ts | 37 +- .../decorators/prop/prop-basic-type.test.ts | 21 +- .../decorators/prop/prop-complex-type.test.ts | 25 +- .../decorators/prop/state-to-prop.test.ts | 39 +- .../provide-annotation-usage.test.ts | 49 +- .../provide-basic-type.test.ts | 21 +- .../provide-complex-type.test.ts | 25 +- .../resource/resource-in-build.test.ts | 43 +- .../resource/resource-in-property.test.ts | 26 +- .../reusable/reusable-basic.test.ts | 41 +- .../reusable/reusable-complex.test.ts | 43 +- .../decorators/state/state-basic-type.test.ts | 21 +- .../state/state-complex-type.test.ts | 25 +- .../decorators/state/state-to-state.test.ts | 27 +- .../storagelink-appstorage.test.ts | 35 +- .../storagelink-complex-type.test.ts | 25 +- .../storagelink-primitive-type.test.ts | 21 +- .../storageprop-appstorage.test.ts | 35 +- .../storageprop-complex-type.test.ts | 25 +- .../storageprop-primitive-type.test.ts | 21 +- .../decorators/watch/watch-basic.test.ts | 63 +- .../xcomponent/xcomponent-basic.test.ts | 31 +- arkui-plugins/test/utils/artkts-config.ts | 92 +-- arkui-plugins/test/utils/cache.ts | 47 +- arkui-plugins/test/utils/compile.ts | 203 ++++++- arkui-plugins/test/utils/global.ts | 76 ++- .../hash-generator.ts} | 67 +-- arkui-plugins/test/utils/path-config.ts | 11 +- arkui-plugins/test/utils/plugin-driver.ts | 38 +- arkui-plugins/test/utils/plugin-tester.ts | 193 +++---- .../plugins/builder-lambda-no-recheck.ts | 3 +- .../test/utils/plugins/memo-no-recheck.ts | 2 +- arkui-plugins/test/utils/plugins/recheck.ts | 2 +- .../test/utils/plugins/struct-no-recheck.ts | 3 +- .../test/utils/plugins/struct-to-component.ts | 2 +- .../test/utils/plugins/ui-no-recheck.ts | 3 +- arkui-plugins/test/utils/safe-types.ts | 10 +- .../serializable.ts} | 21 +- arkui-plugins/test/utils/shared-types.ts | 114 ++++ arkui-plugins/test/utils/task-processor.ts | 541 ++++++++++++++++++ arkui-plugins/tsconfig.json | 7 +- .../builder-lambda-transformer.ts | 15 +- .../builder-lambda-translators/factory.ts | 228 +++++--- .../builder-lambda-translators/utils.ts | 51 +- .../ui-plugins/checked-transformer.ts | 436 ++------------ .../ui-plugins/component-transformer.ts | 253 ++++---- .../ui-plugins/entry-translators/factory.ts | 6 +- .../ui-plugins/entry-translators/utils.ts | 2 +- arkui-plugins/ui-plugins/import-collector.ts | 103 ++++ arkui-plugins/ui-plugins/index.ts | 24 +- .../ui-plugins/preprocessor-transform.ts | 61 +- .../ui-plugins/property-translators/base.ts | 93 +-- .../property-translators/builderParam.ts | 89 ++- .../property-translators/consume.ts | 62 +- .../property-translators/factory.ts | 324 ++++++++++- .../ui-plugins/property-translators/index.ts | 134 +++-- .../ui-plugins/property-translators/link.ts | 76 ++- .../property-translators/localstoragelink.ts | 109 +++- .../property-translators/localstorageprop.ts | 119 +++- .../property-translators/objectlink.ts | 68 ++- .../property-translators/observedTrack.ts | 75 ++- .../ui-plugins/property-translators/prop.ts | 74 ++- .../property-translators/provide.ts | 65 ++- .../property-translators/regularProperty.ts | 33 +- .../ui-plugins/property-translators/state.ts | 78 ++- .../property-translators/storageProp.ts | 75 ++- .../property-translators/storagelink.ts | 75 ++- .../ui-plugins/property-translators/types.ts | 6 + .../ui-plugins/property-translators/utils.ts | 313 +++++++--- .../ui-plugins/struct-translators/factory.ts | 448 ++++++++++++--- .../struct-translators/struct-transformer.ts | 193 ++----- .../ui-plugins/struct-translators/utils.ts | 33 +- arkui-plugins/ui-plugins/ui-factory.ts | 207 +++++-- arkui-plugins/ui-plugins/utils.ts | 253 ++++++-- koala-wrapper/native/include/common.h | 2 +- koala-wrapper/native/src/bridges.cc | 116 +++- koala-wrapper/native/src/common.cc | 18 +- koala-wrapper/native/src/generated/bridges.cc | 91 +-- koala-wrapper/src/Es2pandaNativeModule.ts | 48 +- .../src/arkts-api/factory/nodeFactory.ts | 18 +- koala-wrapper/src/arkts-api/index.ts | 6 +- .../node-utilities/AnnotationDeclaration.ts | 41 +- .../node-utilities/TSInterfaceDeclaration.ts | 6 +- .../arkts-api/node-utilities/TryStatement.ts | 41 ++ koala-wrapper/src/arkts-api/peers/AstNode.ts | 103 ++-- koala-wrapper/src/arkts-api/peers/Context.ts | 54 +- koala-wrapper/src/arkts-api/peers/Program.ts | 21 +- koala-wrapper/src/arkts-api/types.ts | 2 +- .../src/arkts-api/utilities/performance.ts | 56 +- .../src/arkts-api/utilities/public.ts | 60 +- koala-wrapper/src/arkts-api/visitor.ts | 89 +-- koala-wrapper/src/generated/Es2pandaEnums.ts | 2 +- .../src/generated/Es2pandaNativeModule.ts | 24 +- .../src/generated/peers/LabelPair.ts | 31 +- .../src/generated/peers/ScriptFunction.ts | 2 +- .../src/generated/peers/TryStatement.ts | 26 +- 177 files changed, 5626 insertions(+), 3859 deletions(-) rename arkui-plugins/{test/local/@ohos.arkui.component.units.d.ets => common/declaration-collector.ts} (38%) rename arkui-plugins/{test/local/@ohos.arkui.component.common.d.ets => common/safe-types.ts} (31%) rename arkui-plugins/test/{local/@ohos.arkui.external.resource.d.ets => demo/mock/common-utils/annotation.ets} (66%) delete mode 100644 arkui-plugins/test/local/@ohos.arkui.component.customComponent.d.ets delete mode 100644 arkui-plugins/test/local/@ohos.arkui.component.styledString.d.ets delete mode 100644 arkui-plugins/test/local/@ohos.arkui.component.text.d.ets delete mode 100644 arkui-plugins/test/local/@ohos.arkui.stateManagement.common.d.ets delete mode 100644 arkui-plugins/test/local/@ohos.arkui.stateManagement.runtime.d.ets delete mode 100644 arkui-plugins/test/local/@ohos.arkui.stateManagement.storage.d.ets delete mode 100644 arkui-plugins/test/test.log rename arkui-plugins/test/{local/@ohos.arkui.component.enums.d.ets => utils/hash-generator.ts} (36%) rename arkui-plugins/test/{local/@ohos.arkui.stateManagement.d.ets => utils/serializable.ts} (54%) create mode 100644 arkui-plugins/test/utils/shared-types.ts create mode 100644 arkui-plugins/test/utils/task-processor.ts create mode 100644 arkui-plugins/ui-plugins/import-collector.ts rename arkui-plugins/test/local/@ohos.arkui.component.column.d.ets => koala-wrapper/src/arkts-api/node-utilities/AnnotationDeclaration.ts (39%) create mode 100644 koala-wrapper/src/arkts-api/node-utilities/TryStatement.ts rename arkui-plugins/test/local/@ohos.arkui.component.d.ets => koala-wrapper/src/generated/peers/LabelPair.ts (52%) diff --git a/arkui-plugins/common/arkts-utils.ts b/arkui-plugins/common/arkts-utils.ts index 771442543..6e9a5e38b 100644 --- a/arkui-plugins/common/arkts-utils.ts +++ b/arkui-plugins/common/arkts-utils.ts @@ -79,21 +79,3 @@ export function matchPrefix(prefixCollection: (string | RegExp)[], name: string) } return false; } - -export function updateStructMetadata( - structInfo: arkts.StructInfo, - propertyName: string, - properties: string[], - modifiers: arkts.Es2pandaModifierFlags, - hasStateManagementType?: boolean -): arkts.StructInfo { - const metadata: Record = structInfo.metadata ?? {}; - metadata[propertyName] = { - name: propertyName, - properties, - modifiers, - hasStateManagementType, - }; - structInfo.metadata = metadata; - return structInfo; -} diff --git a/arkui-plugins/test/local/@ohos.arkui.component.units.d.ets b/arkui-plugins/common/declaration-collector.ts similarity index 38% rename from arkui-plugins/test/local/@ohos.arkui.component.units.d.ets rename to arkui-plugins/common/declaration-collector.ts index c6a98e628..e7507328e 100644 --- a/arkui-plugins/test/local/@ohos.arkui.component.units.d.ets +++ b/arkui-plugins/common/declaration-collector.ts @@ -1,10 +1,10 @@ /* - * Copyright (C) 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -12,18 +12,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import * as arkts from '@koalaui/libarkts'; -import { Resource } from "@ohos.arkui.external.resource" -import { Color } from "@ohos.arkui.component.enums"; +export class DeclarationCollector { + public fromExternalSourceNames: Set; + static instance: DeclarationCollector; -export type PX = string; -export type VP = string | number; -export type FP = string; -export type LPX = string; -export type Percentage = string; + private constructor() { + this.fromExternalSourceNames = new Set(); + } -export type Dimension = PX | VP | FP | LPX | Percentage | Resource; + static getInstance(): DeclarationCollector { + if (!this.instance) { + this.instance = new DeclarationCollector(); + } + return this.instance; + } -export type Length = string | number | Resource; + collect(decl: arkts.AstNode | undefined): void { + if (!decl) return; + const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + this.fromExternalSourceNames.add(moduleName); + } -export type ResourceColor = Color | number | string | Resource; \ No newline at end of file + reset(): void { + this.fromExternalSourceNames.clear(); + } +} \ No newline at end of file diff --git a/arkui-plugins/common/plugin-context.ts b/arkui-plugins/common/plugin-context.ts index f0ad9ccb4..95843cb7b 100644 --- a/arkui-plugins/common/plugin-context.ts +++ b/arkui-plugins/common/plugin-context.ts @@ -74,10 +74,23 @@ export class PluginContext { } } +export interface DependentModuleConfig { + packageName: string; + moduleName: string; + moduleType: string; + modulePath: string; + sourceRoots: string[]; + entryFile: string; + language: string, + declFilesPath?: string, + dependencies?: string[] +} + export interface ProjectConfig { bundleName: string; moduleName: string; cachePath: string; + dependentModuleList: DependentModuleConfig[]; } export type PluginHandlerFunction = () => void; diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index d4667b424..33c27405c 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -28,14 +28,13 @@ export const EXTERNAL_SOURCE_PREFIX_NAMES: (string | RegExp)[] = [ /ability\..*/, ]; +export const ARKUI_IMPORT_PREFIX_NAMES: (string | RegExp)[] = [/@ohos\..*/, /arkui\..*/]; + export const ARKUI_COMPONENT_IMPORT_NAME: string = '@ohos.arkui.component'; export const ARKUI_STATEMANAGEMENT_IMPORT_NAME: string = '@ohos.arkui.stateManagement'; -export const EXTERNAL_SOURCE_ALLOWED_IMPORT_INSERT_NAMES: string[] = [ - ARKUI_COMPONENT_IMPORT_NAME, - ARKUI_STATEMANAGEMENT_IMPORT_NAME, -]; +export const KOALAUI_COMMON_IMPORT_NAME: string = '@koalaui.runtime.common'; export const IMPORT_SOURCE_MAP: Map> = new Map>([ ['@ohos.arkui.component', new Set(['$r', '$rawfile', '_r', '_rawfile', 'Bindable'])], @@ -77,31 +76,73 @@ export const IMPORT_SOURCE_MAP: Map> = new Map = new Map([ - ['$r', ['_r']], - ['$rawfile', ['_rawfile']], - ['State', ['StateDecoratedVariable']], - ['Link', ['LinkDecoratedVariable', 'DecoratedV1VariableBase']], - ['Prop', ['PropDecoratedVariable']], - ['Provide', ['ProvideDecoratedVariable']], - ['Consume', ['ConsumeDecoratedVariable']], - ['StorageProp', ['StoragePropDecoratedVariable']], - ['StorageLink', ['StorageLinkDecoratedVariable']], - ['LocalStorageLink', ['StorageLinkState', 'MutableState', 'observableProxy']], - ['LocalStorageProp', ['StorageLinkState', 'SyncedProperty', 'observableProxy', 'propState']], - ['ObjectLink', ['ObjectLinkDecoratedVariable']], - ['Observed', ['MutableStateMeta', 'BackingValue', 'setObservationDepth', 'IObservedObject', 'int32', 'WatchIdType', 'SubscribedWatches']], - ['Track', ['MutableStateMeta', 'BackingValue', 'setObservationDepth', 'IObservedObject', 'int32', 'WatchIdType', 'SubscribedWatches']], - ['$$', ['Bindable']], +export const IMPORT_SOURCE_MAP_V2: Map = new Map([ + ['$r', ARKUI_COMPONENT_IMPORT_NAME], + ['$rawfile', ARKUI_COMPONENT_IMPORT_NAME], + ['_r', ARKUI_COMPONENT_IMPORT_NAME], + ['_rawfile', ARKUI_COMPONENT_IMPORT_NAME], + ['Bindable', ARKUI_COMPONENT_IMPORT_NAME], + ['State', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['Prop', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['Provide', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['Consume', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StorageLink', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StorageProp', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['LocalStorageLink', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['LocalStorageProp', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['Watch', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['ObjectLink', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StateDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['MutableState', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['contextLocalStateOf', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['contextLocal', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['observableProxy', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['SyncedProperty', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['objectLinkState', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['propState', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['AppStorageLinkState', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StorageLinkState', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['DecoratedV1VariableBase', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['LinkDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['PropDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StorageLinkDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['StoragePropDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['ProvideDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['ConsumeDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['ObjectLinkDecoratedVariable', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['MutableStateMeta', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['BackingValue', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['setObservationDepth', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['IObservedObject', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['WatchIdType', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['SubscribedWatches', ARKUI_STATEMANAGEMENT_IMPORT_NAME], + ['int32', KOALAUI_COMMON_IMPORT_NAME], ]); +export const OUTPUT_DEPENDENCY_MAP: Map = new Map([ + ['$r', []], + ['$rawfile', []], + ['State', []], + ['Link', []], + ['Prop', []], + ['Provide', []], + ['Consume', []], + ['StorageProp', []], + ['StorageLink', []], + ['LocalStorageLink', []], + ['LocalStorageProp', []], + ['ObjectLink', []], + ['Observed', []], + ['Track', []], + ['$$', []], +]); export enum InteroperAbilityNames { ARKTS_1_1 = '1.1', diff --git a/arkui-plugins/common/program-visitor.ts b/arkui-plugins/common/program-visitor.ts index a0a35f6c6..54e0a298d 100644 --- a/arkui-plugins/common/program-visitor.ts +++ b/arkui-plugins/common/program-visitor.ts @@ -17,10 +17,11 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor, VisitorOptions } from './abstract-visitor'; import { matchPrefix } from './arkts-utils'; import { debugDump, getDumpFileName } from './debug'; -import { InteroperAbilityNames, ARKUI_COMPONENT_IMPORT_NAME } from './predefines'; +import { InteroperAbilityNames, ARKUI_COMPONENT_IMPORT_NAME, ARKUI_IMPORT_PREFIX_NAMES } from './predefines'; import { PluginContext } from './plugin-context'; import { LegacyTransformer } from '../ui-plugins/legacy-transformer'; import { ComponentTransformer } from '../ui-plugins/component-transformer'; +import { DeclarationCollector } from './declaration-collector'; export interface ProgramVisitorOptions extends VisitorOptions { pluginName: string; @@ -80,7 +81,7 @@ function sortExternalSources(externalSources: arkts.ExternalSource[]): arkts.Ext export interface StructMap { [key: string]: string; -} +} export class ProgramVisitor extends AbstractVisitor { private readonly pluginName: string; @@ -113,7 +114,7 @@ export class ProgramVisitor extends AbstractVisitor { this.legacyModuleList = []; } - getLegacyModule(): void { + private getLegacyModule(): void { const moduleList = this.pluginContext?.getProjectConfig()?.dependentModuleList; if (moduleList === undefined) { return; @@ -125,36 +126,40 @@ export class ProgramVisitor extends AbstractVisitor { continue; } if (!this.legacyStructMap.has(moduleName)) { - this.legacyStructMap.set(moduleName, {}); + this.legacyStructMap.set(moduleName, {}); this.legacyModuleList.push(moduleName); } } } - dumpHeaders( - currProgram: arkts.Program, + private dumpExternalSource( + script: arkts.AstNode, name: string, cachePath: string | undefined, prefixName: string, extensionName: string ): void { debugDump( - currProgram.astNode.dumpSrc(), - getDumpFileName(this.state, prefixName, undefined, name), + script.dumpSrc(), + getDumpFileName(this.state, prefixName, undefined, name), true, cachePath, extensionName ); } - programVisitor(program: arkts.Program): arkts.Program { - const skipPrefixes: (string | RegExp)[] = this.skipPrefixNames; + private visitExternalSources( + program: arkts.Program, + programQueue: arkts.Program[], + excludeCheck?: (name: string) => boolean + ): void { const visited = new Set(); - const queue: arkts.Program[] = [program]; + const queue: arkts.Program[] = programQueue; this.getLegacyModule(); + arkts.Performance.getInstance().createEvent(`${this.state}-external-source`); while (queue.length > 0) { const currProgram = queue.shift()!; - if (visited.has(currProgram.peer)) { + if (visited.has(currProgram.peer) || currProgram.isASTLowered()) { continue; } if (currProgram.peer !== program.peer) { @@ -170,16 +175,17 @@ export class ProgramVisitor extends AbstractVisitor { } } } else { - this.dumpHeaders(currProgram, name, cachePath, 'Ori', program.programFileNameWithExtension); + const extensionName: string = program.fileNameWithExtension; + this.dumpExternalSource(currProgram.astNode, name, cachePath, 'ORI', extensionName); const script = this.visitor(currProgram.astNode, currProgram, name); if (script) { - this.dumpHeaders(currProgram, name, cachePath, this.pluginName, program.programFileNameWithExtension); + this.dumpExternalSource(script, name, cachePath, this.pluginName, extensionName); } } } visited.add(currProgram.peer); - for (const externalSource of sortExternalSources(currProgram.externalSources)) { - if (matchPrefix(skipPrefixes, externalSource.getName())) { + for (const externalSource of currProgram.externalSources) { + if (!!excludeCheck && excludeCheck(externalSource.getName())) { continue; } const nextProgramArr: arkts.Program[] = externalSource.programs ?? []; @@ -191,105 +197,117 @@ export class ProgramVisitor extends AbstractVisitor { } } } - const hasLegacy = this.legacyStructMap.size ? true : false; + arkts.Performance.getInstance().stopEvent(`${this.state}-external-source`, false); + } + + programVisitor(program: arkts.Program): arkts.Program { + const excludeCheck = (name: string) => { + return matchPrefix(this.skipPrefixNames, name); + }; + this.visitExternalSources(program, [program], excludeCheck); + + arkts.Performance.getInstance().createEvent(`${this.state}-source`); let programScript = program.astNode; - programScript = this.visitor(programScript, program, this.externalSourceName, hasLegacy); + programScript = this.visitor(programScript, program, this.externalSourceName); + arkts.Performance.getInstance().stopEvent(`${this.state}-source`, false); + const visitorsToReset = flattenVisitorsInHooks(this.hooks, this.state); visitorsToReset.forEach((visitor) => visitor.reset()); + return program; } - preVisitor( + private preVisitor( + hook: ProgramHookLifeCycle | undefined, node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string ): void { - const isExternal: boolean = !!externalSourceName; - let hook: ProgramHookLifeCycle | undefined = isExternal ? this.hooks?.external : this.hooks?.source; let script: arkts.EtsScript = node as arkts.EtsScript; - const preVisitors = hook?.pre?.visitors ?? []; for (const transformer of preVisitors) { - transformer.isExternal = isExternal; - transformer.externalSourceName = externalSourceName; - transformer.program = program; - transformer.visitor(script); - if (!this.hooks?.external?.pre?.resetAfter) { - transformer.reset(); - } + this.visitTransformer(transformer, script, externalSourceName, program); + if (!this.hooks?.external?.pre?.resetAfter) transformer.reset(); } } - postVisitor( + private postVisitor( + hook: ProgramHookLifeCycle | undefined, node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string ): void { - const isExternal: boolean = !!externalSourceName; - let hook: ProgramHookLifeCycle | undefined = isExternal ? this.hooks?.external : this.hooks?.source; let script: arkts.EtsScript = node as arkts.EtsScript; - const postVisitors = hook?.post?.visitors ?? []; for (const transformer of postVisitors) { - transformer.isExternal = isExternal; - transformer.externalSourceName = externalSourceName; - transformer.program = program; - transformer.visitor(script); - if (!this.hooks?.external?.pre?.resetAfter) { - transformer.reset(); - } + this.visitTransformer(transformer, script, externalSourceName, program); + if (!this.hooks?.external?.pre?.resetAfter) transformer.reset(); } } - visitor( - node: arkts.AstNode, - program?: arkts.Program, - externalSourceName?: string, - hasLegacy: boolean = false - ): arkts.EtsScript { + visitor(node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string): arkts.EtsScript { + arkts.Performance.getInstance().createEvent(`${this.state}-${externalSourceName ?? 'SOURCE'}`); + let hook: ProgramHookLifeCycle | undefined; + let script: arkts.EtsScript = node as arkts.EtsScript; let count: number = 0; const isExternal: boolean = !!externalSourceName; // pre-run visitors - this.preVisitor(node, program, externalSourceName); + hook = isExternal ? this.hooks?.external : this.hooks?.source; + this.preVisitor(hook, node, program, externalSourceName); for (const transformer of this.visitors) { - transformer.isExternal = isExternal; - transformer.externalSourceName = externalSourceName; - transformer.program = program; - if (hasLegacy && transformer instanceof ComponentTransformer) { + if (this.legacyStructMap.size > 0 && transformer instanceof ComponentTransformer) { transformer.registerMap(this.legacyStructMap); } - script = transformer.visitor(script) as arkts.EtsScript; + this.visitTransformer(transformer, script, externalSourceName, program); transformer.reset(); + arkts.Performance.getInstance().createEvent('set-all-parent'); arkts.setAllParents(script); + arkts.Performance.getInstance().stopEvent('set-all-parent', false); if (!transformer.isExternal) { debugDump( script.dumpSrc(), getDumpFileName(this.state, this.pluginName, count, transformer.constructor.name), true, this.pluginContext?.getProjectConfig()?.cachePath, - program!.programFileNameWithExtension + program!.fileNameWithExtension ); count += 1; } } // post-run visitors - this.postVisitor(node, program, externalSourceName); + hook = isExternal ? this.hooks?.external : this.hooks?.source; + this.postVisitor(hook, node, program, externalSourceName); + arkts.Performance.getInstance().stopEvent(`${this.state}-${externalSourceName ?? 'SOURCE'}`, false); return script; } - visitorLegacy( - node: arkts.AstNode, - program?: arkts.Program, - externalSourceName?: string, - ): string[] { - const visitor = new LegacyTransformer(); - const script = visitor.visitor(node) as arkts.EtsScript; - const structList = visitor.getList(); + private visitorLegacy(node: arkts.AstNode, program?: arkts.Program, externalSourceName?: string): string[] { + const transformer = new LegacyTransformer(); + transformer.isExternal = !!externalSourceName; + transformer.externalSourceName = externalSourceName; + transformer.program = program; + const script = transformer.visitor(node) as arkts.EtsScript; + const structList = transformer.getList(); return structList; } + + private visitTransformer( + transformer: AbstractVisitor, + script: arkts.EtsScript, + externalSourceName?: string, + program?: arkts.Program + ): arkts.EtsScript { + arkts.Performance.getInstance().createEvent(transformer.constructor.name); + transformer.isExternal = !!externalSourceName; + transformer.externalSourceName = externalSourceName; + transformer.program = program; + const newScript = transformer.visitor(script) as arkts.EtsScript; + arkts.Performance.getInstance().stopEvent(transformer.constructor.name, false); + return newScript; + } } diff --git a/arkui-plugins/test/local/@ohos.arkui.component.common.d.ets b/arkui-plugins/common/safe-types.ts similarity index 31% rename from arkui-plugins/test/local/@ohos.arkui.component.common.d.ets rename to arkui-plugins/common/safe-types.ts index 2ff6ea60a..899ef0c39 100644 --- a/arkui-plugins/test/local/@ohos.arkui.component.common.d.ets +++ b/arkui-plugins/common/safe-types.ts @@ -1,10 +1,10 @@ /* - * Copyright (C) 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,43 +13,31 @@ * limitations under the License. */ -import { Dimension, Length, ResourceColor } from "@ohos.arkui.component.units"; -import { IlluminatedType } from "@ohos.arkui.component.enums"; -import { memo } from '@ohos.arkui.stateManagement.runtime'; - -@Retention({policy: "SOURCE"}) -export @interface BuilderLambda { - value: string -} - -@Retention({policy: "SOURCE"}) -export declare @interface ComponentBuilder {}; - -@Retention({policy: "SOURCE"}) -export declare @interface BuilderParam {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Builder {}; - -export declare interface LightSource { - positionX: Dimension; - positionY: Dimension; - positionZ: Dimension; - intensity: number; - color?: ResourceColor; -} - -export declare interface PointLightStyle { - lightSource?: LightSource; - illuminated?: IlluminatedType; - bloom?: number; -} - -export declare interface CommonMethod { - @memo - width(w: Length): this; - @memo - height(h: Length): this; - @memo - backgroundColor(color: ResourceColor): this; -} \ No newline at end of file +import * as arkts from '@koalaui/libarkts'; + +export type PartialExcept = Partial & Pick; + +type PartialArray = T extends readonly any[] | any[] ? T | undefined : T; +type PartialAstNode = T extends arkts.AstNode ? T | undefined : T; +type PartialObject = T extends object ? { [P in keyof T]?: T[P] } : T; +type PartialPrimitive = T; + +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; +}; + +type NestedKey = { + [P in keyof T]: P extends K ? T[P] : T[P] extends object ? NestedKey : T[P]; + }; + +export type PickNested = { + [P in keyof T]: P extends K ? T[P] : T[P] extends object ? NestedKey : T[P]; +}; + +export type PartialNestedExcept = PartialNested> & PickNested; \ No newline at end of file diff --git a/arkui-plugins/interop-plugins/index.ts b/arkui-plugins/interop-plugins/index.ts index 404892c34..21c971ce0 100644 --- a/arkui-plugins/interop-plugins/index.ts +++ b/arkui-plugins/interop-plugins/index.ts @@ -88,7 +88,6 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { program = programVisitor.programVisitor(program); script = program.astNode; - arkts.GlobalInfo.getInfoInstance()?.reset(); arkts.recheckSubtree(script); this.setArkTSAst(script); debugLog('interopTransform:checked exit'); diff --git a/arkui-plugins/memo-plugins/function-transformer.ts b/arkui-plugins/memo-plugins/function-transformer.ts index fa4a06bc4..596077c04 100644 --- a/arkui-plugins/memo-plugins/function-transformer.ts +++ b/arkui-plugins/memo-plugins/function-transformer.ts @@ -52,6 +52,7 @@ import { import { ParameterTransformer } from './parameter-transformer'; import { ReturnTransformer } from './return-transformer'; import { SignatureTransformer } from './signature-transformer'; +// import { DeclarationCollector } from '../common/declaration-collector'; interface ScopeInfo extends MemoInfo { regardAsSameScope?: boolean; @@ -70,6 +71,9 @@ export class FunctionTransformer extends AbstractVisitor { private readonly returnTransformer: ReturnTransformer; private readonly signatureTransformer: SignatureTransformer; + /* Tracking whether should import `__memo_context_type` and `__memo_id_type` */ + private modified = false; + constructor(options: FunctionTransformerOptions) { super(options); this.positionalIdTracker = options.positionalIdTracker; @@ -85,6 +89,7 @@ export class FunctionTransformer extends AbstractVisitor { super.reset(); this.scopes = []; this.stable = 0; + this.modified = false; this.parameterTransformer.reset(); this.returnTransformer.reset(); this.signatureTransformer.reset(); @@ -211,7 +216,7 @@ export class FunctionTransformer extends AbstractVisitor { checkMemoCallInFunction() { const scope = this.scopes[this.scopes.length - 1]; - if (scope?.regardAsSameScope === false && scope?.isMemo == false) { + if (scope?.regardAsSameScope === false && scope?.isMemo === false) { console.error(`Attempt to call @memo-function`); throw 'Invalid @memo usage'; } @@ -222,6 +227,9 @@ export class FunctionTransformer extends AbstractVisitor { if (!scriptFunction.body || !arkts.isBlockStatement(scriptFunction.body)) { return scriptFunction; } + if (this.parameterTransformer.isTracked(scriptFunction.body)) { + return scriptFunction; + } if (hasMemoIntrinsicAnnotation(scriptFunction) || hasMemoEntryAnnotation(scriptFunction)) { return scriptFunction; } @@ -253,6 +261,8 @@ export class FunctionTransformer extends AbstractVisitor { afterReturnTransformer, returnTypeInfo.node ); + this.modified = true; + this.parameterTransformer.track(updateScriptFunction.body); return updateScriptFunction; } @@ -265,13 +275,15 @@ export class FunctionTransformer extends AbstractVisitor { hasMemoIntrinsicAnnotation(node.scriptFunction) || hasMemoEntryAnnotation(node.scriptFunction); if (isMemo && node.scriptFunction.body) { + const hasIntrinsic = hasMemoIntrinsicAnnotation(node.scriptFunction); updateMethod = arkts.factory.updateMethodDefinition( node, node.kind, node.name, arkts.factory.createFunctionExpression( this.signatureTransformer.visitor( - removeMemoAnnotation(this.updateScriptFunction(node.scriptFunction, node.name.name)) + removeMemoAnnotation(this.updateScriptFunction(node.scriptFunction, node.name.name)), + hasIntrinsic ) ), node.modifiers, @@ -290,6 +302,7 @@ export class FunctionTransformer extends AbstractVisitor { if (!!updateOverloads) { updateMethod.setOverloads(castOverloadsToMethods(updateOverloads)); } + this.modified ||= this.signatureTransformer.modified; return updateMethod; } @@ -307,6 +320,7 @@ export class FunctionTransformer extends AbstractVisitor { this.enterAnonymousScope(it.scriptFunction); const res = this.updateScriptFunction(it.scriptFunction); this.exitAnonymousScope(); + this.modified = true; return arkts.factory.updateArrowFunction(it, res); } return it; @@ -318,10 +332,12 @@ export class FunctionTransformer extends AbstractVisitor { ...updatedArguments, ]; } + this.modified = true; return arkts.factory.updateCallExpression(node, node.expression, node.typeArguments, updatedArguments); } private updateDeclaredCallWithName(node: arkts.CallExpression, name: string): arkts.CallExpression { + this.modified = true; return factory.insertHiddenArgumentsToCall(node, this.positionalIdTracker.id(name)); } @@ -333,15 +349,18 @@ export class FunctionTransformer extends AbstractVisitor { this.signatureTransformer.visitor(node.expression.scriptFunction) ); } + const that = this; const updatedArguments: arkts.AstNode[] = node.arguments.map((it) => { if (arkts.isArrowFunctionExpression(it) && isMemoArrowFunction(it)) { - this.enterAnonymousScope(it.scriptFunction); - const res = this.updateScriptFunction(it.scriptFunction); - this.exitAnonymousScope(); + that.enterAnonymousScope(it.scriptFunction); + const res = that.updateScriptFunction(it.scriptFunction); + that.exitAnonymousScope(); + that.modified = true; return arkts.factory.updateArrowFunction(it, res); } return it; }); + this.modified ||= this.signatureTransformer.modified; return arkts.factory.updateCallExpression(node, newExpression, node.typeArguments, updatedArguments); } @@ -365,6 +384,7 @@ export class FunctionTransformer extends AbstractVisitor { this.exitAnonymousScope(); const newNode = this.updateAnonymousCallWithMemoParams(node); + this.modified = true; return arkts.factory.updateCallExpression( node, arkts.factory.updateArrowFunction(expression, res), @@ -433,6 +453,7 @@ export class FunctionTransformer extends AbstractVisitor { throw 'Invalid @memo usage'; } + this.modified = true; return arkts.factory.updateClassProperty( node, node.key, @@ -452,12 +473,14 @@ export class FunctionTransformer extends AbstractVisitor { this.exitAnonymousScope(); if (!scope.isMemo) { if (!!node.typeAnnotation) { - return arkts.factory.updateTSTypeAliasDeclaration( + const newNode = arkts.factory.updateTSTypeAliasDeclaration( node, node.id, node.typeParams, this.signatureTransformer.visitor(node.typeAnnotation) ); + this.modified ||= this.signatureTransformer.modified; + return newNode; } return node; } @@ -468,6 +491,7 @@ export class FunctionTransformer extends AbstractVisitor { throw 'Invalid @memo usage'; } + this.modified = true; return arkts.factory.updateTSTypeAliasDeclaration(node, node.id, node.typeParams, typeAnnotation); } @@ -486,6 +510,7 @@ export class FunctionTransformer extends AbstractVisitor { const res = this.updateScriptFunction(node.scriptFunction, node.scriptFunction.id?.name); this.exitAnonymousScope(); + this.modified = true; return arkts.factory.updateArrowFunction(node, this.signatureTransformer.visitor(res)); } @@ -528,6 +553,7 @@ export class FunctionTransformer extends AbstractVisitor { initializer = arkts.factory.updateArrowFunction(initializer, res); } + this.modified = true; return arkts.factory.updateVariableDeclarator( node, node.flag, @@ -560,6 +586,7 @@ export class FunctionTransformer extends AbstractVisitor { throw 'Invalid @memo usage'; } + this.modified = true; return arkts.factory.updateTSAsExpression( node, arkts.factory.updateArrowFunction(expr, res), @@ -587,6 +614,7 @@ export class FunctionTransformer extends AbstractVisitor { const res = this.updateScriptFunction(value.scriptFunction, value.scriptFunction.id?.name); this.exitAnonymousScope(); + this.modified = true; return arkts.factory.updateProperty(node, key, arkts.factory.updateArrowFunction(value, res)); } @@ -609,6 +637,7 @@ export class FunctionTransformer extends AbstractVisitor { const res = this.updateScriptFunction(right.scriptFunction, right.scriptFunction.id?.name); this.exitAnonymousScope(); + this.modified = true; return arkts.factory.updateAssignmentExpression( node, node.left!, @@ -649,6 +678,9 @@ export class FunctionTransformer extends AbstractVisitor { const thisAttribute = findThisAttribute(node.left!)!; return this.updateThisAttributeAssignment(node, thisAttribute, node.right); } + if (arkts.isEtsScript(node) && this.modified) { + factory.createContextTypesImportDeclaration(this.program); + } return node; } } diff --git a/arkui-plugins/memo-plugins/index.ts b/arkui-plugins/memo-plugins/index.ts index 58f785dbd..d1f8cbf86 100644 --- a/arkui-plugins/memo-plugins/index.ts +++ b/arkui-plugins/memo-plugins/index.ts @@ -29,7 +29,7 @@ export function unmemoizeTransform(): Plugins { name: 'memo-plugin', checked(this: PluginContext) { console.log('[MEMO PLUGIN] AFTER CHECKED ENTER'); - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; let script = program.astNode; @@ -41,7 +41,7 @@ export function unmemoizeTransform(): Plugins { getDumpFileName(0, 'SRC', 5, 'MEMO_AfterCheck_Begin'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('memo-checked'); @@ -70,7 +70,7 @@ export function unmemoizeTransform(): Plugins { program = programVisitor.programVisitor(program); script = program.astNode; - arkts.Performance.getInstance().stopEvent('memo-checked', true); + arkts.Performance.getInstance().stopEvent("memo-checked", false); debugLog('[AFTER MEMO SCRIPT] script: ', script.dumpSrc()); debugDump( @@ -78,14 +78,17 @@ export function unmemoizeTransform(): Plugins { getDumpFileName(0, 'SRC', 6, 'MEMO_AfterCheck_End'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('memo-recheck'); arkts.recheckSubtree(script); - arkts.Performance.getInstance().stopEvent('memo-recheck', true); + arkts.Performance.getInstance().stopEvent("memo-recheck", false); - arkts.Performance.getInstance().clearAllEvents(); + arkts.Performance.getInstance().clearAllEvents(true); + arkts.Performance.getInstance().visualizeEvents(true); + arkts.Performance.getInstance().clearHistory(); + arkts.Performance.getInstance().clearTotalDuration(); this.setArkTSAst(script); console.log('[MEMO PLUGIN] AFTER CHECKED EXIT'); diff --git a/arkui-plugins/memo-plugins/memo-factory.ts b/arkui-plugins/memo-plugins/memo-factory.ts index c1288e7eb..fcc8f97d2 100644 --- a/arkui-plugins/memo-plugins/memo-factory.ts +++ b/arkui-plugins/memo-plugins/memo-factory.ts @@ -38,7 +38,6 @@ export class factory { arkts.factory.createIdentifier(RuntimeNames.ID_TYPE) ); } - // TODO: Currently, import declaration can only be inserted at after-parsed stage. static createContextTypesImportDeclaration(program?: arkts.Program): void { const source: arkts.StringLiteral = arkts.factory.createStringLiteral(RuntimeNames.CONTEXT_TYPE_DEFAULT_IMPORT); const importDecl: arkts.ETSImportDeclaration = arkts.factory.createImportDeclaration( diff --git a/arkui-plugins/memo-plugins/parameter-transformer.ts b/arkui-plugins/memo-plugins/parameter-transformer.ts index d5e615e99..a46f87a4e 100644 --- a/arkui-plugins/memo-plugins/parameter-transformer.ts +++ b/arkui-plugins/memo-plugins/parameter-transformer.ts @@ -31,6 +31,7 @@ import { RuntimeNames, } from './utils'; import { ReturnTransformer } from './return-transformer'; +// import { DeclarationCollector } from '../common/declaration-collector'; export interface ParameterTransformerOptions extends VisitorOptions { positionalIdTracker: PositionalIdTracker; @@ -46,12 +47,14 @@ export class ParameterTransformer extends AbstractVisitor { private rewriteMemoInfos?: Map; private rewriteThis?: boolean; private skipNode?: arkts.VariableDeclaration; + private visited: Set; private positionalIdTracker: PositionalIdTracker; constructor(options: ParameterTransformerOptions) { super(options); this.positionalIdTracker = options.positionalIdTracker; + this.visited = new Set(); } reset(): void { @@ -60,6 +63,7 @@ export class ParameterTransformer extends AbstractVisitor { this.rewriteCalls = undefined; this.rewriteMemoInfos = undefined; this.skipNode = undefined; + this.visited.clear(); } withThis(flag: boolean): ParameterTransformer { @@ -79,7 +83,7 @@ export class ParameterTransformer extends AbstractVisitor { it.param.identifier.name.startsWith(RuntimeNames.GENSYM) ? it.ident.originalPeer : it.param.originalPeer, - (passArgs: arkts.Expression[]) => { + (passArgs: arkts.Expression[]): arkts.CallExpression => { return factory.createMemoParameterAccessCall(it.ident.name, passArgs); }, ]; @@ -91,7 +95,7 @@ export class ParameterTransformer extends AbstractVisitor { it.param.identifier.name.startsWith(RuntimeNames.GENSYM) ? it.ident.originalPeer : it.param.originalPeer, - () => { + (): arkts.MemberExpression => { return factory.createMemoParameterAccess(it.ident.name); }, ]; @@ -119,6 +123,16 @@ export class ParameterTransformer extends AbstractVisitor { return this; } + track(node: arkts.AstNode | undefined): void { + if (!!node?.peer) { + this.visited.add(node.peer); + } + } + + isTracked(node: arkts.AstNode | undefined): boolean { + return !!node?.peer && this.visited.has(node.peer); + } + private updateArrowFunctionFromVariableDeclareInit( initializer: arkts.ArrowFunctionExpression, returnType: arkts.TypeNode | undefined @@ -141,13 +155,15 @@ export class ParameterTransformer extends AbstractVisitor { returnTypeInfo, this.positionalIdTracker.id() ); - const afterParameterTransformer = new ParameterTransformer({ + const paramaterTransformer = new ParameterTransformer({ positionalIdTracker: this.positionalIdTracker, - }) + }); + const returnTransformer = new ReturnTransformer(); + const afterParameterTransformer = paramaterTransformer .withParameters(parameterIdentifiers) .skip(memoParametersDeclaration) .visitor(body); - const afterReturnTransformer = new ReturnTransformer() + const afterReturnTransformer = returnTransformer .skip(syntheticReturnStatement) .registerReturnTypeInfo(returnTypeInfo) .visitor(afterParameterTransformer); @@ -156,6 +172,9 @@ export class ParameterTransformer extends AbstractVisitor { afterReturnTransformer, returnTypeInfo.node ); + paramaterTransformer.reset(); + returnTransformer.reset(); + this.track(updateScriptFunction.body); return arkts.factory.updateArrowFunction(initializer, updateScriptFunction); } @@ -229,12 +248,12 @@ export class ParameterTransformer extends AbstractVisitor { } if (!!declarator.initializer && arkts.isIdentifier(declarator.initializer)) { const decl = arkts.getPeerDecl(declarator.initializer.originalPeer); - if (decl && that.rewriteIdentifiers?.has(decl.originalPeer)) { + if (decl && that.rewriteIdentifiers?.has(decl.peer)) { return arkts.factory.updateVariableDeclarator( declarator, declarator.flag, declarator.name, - that.rewriteIdentifiers.get(decl.originalPeer)!() + that.rewriteIdentifiers.get(decl.peer)!() ); } } @@ -266,12 +285,12 @@ export class ParameterTransformer extends AbstractVisitor { } if (arkts.isCallExpression(beforeChildren) && arkts.isIdentifier(beforeChildren.expression)) { const decl = arkts.getPeerDecl(beforeChildren.expression.originalPeer); - if (decl && this.rewriteCalls?.has(decl.originalPeer)) { - const updateCall = this.rewriteCalls.get(decl.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) ); - if (this.rewriteMemoInfos?.has(decl.originalPeer)) { - const memoInfo = this.rewriteMemoInfos.get(decl.originalPeer)!; + if (this.rewriteMemoInfos?.has(decl.peer)) { + const memoInfo = this.rewriteMemoInfos.get(decl.peer)!; return this.updateCallReDeclare(updateCall, beforeChildren.expression, memoInfo); } return updateCall; @@ -280,8 +299,8 @@ export class ParameterTransformer extends AbstractVisitor { const node = this.visitEachChild(beforeChildren); if (arkts.isIdentifier(node)) { const decl = arkts.getPeerDecl(node.originalPeer); - if (decl && this.rewriteIdentifiers?.has(decl.originalPeer)) { - return this.rewriteIdentifiers.get(decl.originalPeer)!(); + if (decl && this.rewriteIdentifiers?.has(decl.peer)) { + return this.rewriteIdentifiers.get(decl.peer)!(); } } if (arkts.isThisExpression(node) && this.rewriteThis) { diff --git a/arkui-plugins/memo-plugins/signature-transformer.ts b/arkui-plugins/memo-plugins/signature-transformer.ts index 610114613..d9721c60c 100644 --- a/arkui-plugins/memo-plugins/signature-transformer.ts +++ b/arkui-plugins/memo-plugins/signature-transformer.ts @@ -20,6 +20,8 @@ import { AbstractVisitor } from '../common/abstract-visitor'; function isScriptFunctionFromGetter(node: arkts.ScriptFunction): boolean { return ( + !!node.parent && + !!node.parent.parent && arkts.isFunctionExpression(node.parent) && arkts.isMethodDefinition(node.parent.parent) && node.parent.parent.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET @@ -28,6 +30,8 @@ function isScriptFunctionFromGetter(node: arkts.ScriptFunction): boolean { function isScriptFunctionFromSetter(node: arkts.ScriptFunction): boolean { return ( + !!node.parent && + !!node.parent.parent && arkts.isFunctionExpression(node.parent) && arkts.isMethodDefinition(node.parent.parent) && node.parent.parent.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET @@ -35,6 +39,7 @@ function isScriptFunctionFromSetter(node: arkts.ScriptFunction): boolean { } export class SignatureTransformer extends AbstractVisitor { + /* Tracking whether should import `__memo_context_type` and `__memo_id_type` */ public modified = false; reset(): void { diff --git a/arkui-plugins/memo-plugins/utils.ts b/arkui-plugins/memo-plugins/utils.ts index e013100ac..3e14da1c0 100644 --- a/arkui-plugins/memo-plugins/utils.ts +++ b/arkui-plugins/memo-plugins/utils.ts @@ -14,6 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; import { getCommonPath } from '../path'; +// import { DeclarationCollector } from '../common/declaration-collector'; const common = require(getCommonPath()); const UniqueId = common.UniqueId; @@ -24,10 +25,12 @@ export enum RuntimeNames { ANNOTATION_ENTRY = 'memo_entry', ANNOTATION_INTRINSIC = 'memo_intrinsic', ANNOTATION_STABLE = 'memo_stable', + ANNOTATION_SKIP = 'memo_skip', COMPUTE = 'compute', CONTEXT = '__memo_context', CONTEXT_TYPE = '__memo_context_type', - CONTEXT_TYPE_DEFAULT_IMPORT = '@ohos.arkui.StateManagement.runtime', + CONTEXT_TYPE_DEFAULT_IMPORT = '@ohos.arkui.stateManagement', + MEMO_IMPORT_NAME = 'arkui.stateManagement.runtime', GENSYM = 'gensym%%_', ID = '__memo_id', ID_TYPE = '__memo_id_type', @@ -99,7 +102,8 @@ export class PositionalIdTracker { } export function isMemoAnnotation(node: arkts.AnnotationUsage, memoName: RuntimeNames): boolean { - return node.expr !== undefined && arkts.isIdentifier(node.expr) && node.expr.name === memoName; + if (!(node.expr !== undefined && arkts.isIdentifier(node.expr) && node.expr.name === memoName)) return false; + return true; } export type MemoAstNode = @@ -125,18 +129,16 @@ export function hasMemoEntryAnnotation(node: T): boolean } export function hasMemoStableAnnotation(node: arkts.ClassDefinition): boolean { - return node.annotations.some( - (it) => it.expr !== undefined && arkts.isIdentifier(it.expr) && it.expr.name === RuntimeNames.ANNOTATION_STABLE - ); + return node.annotations.some((it) => isMemoAnnotation(it, RuntimeNames.ANNOTATION_STABLE)); +} + +export function hasMemoSkipAnnotation(node: arkts.ETSParameterExpression): boolean { + return node.annotations.some((it) => isMemoAnnotation(it, RuntimeNames.ANNOTATION_SKIP)); } export function removeMemoAnnotation(node: T): T { const newAnnotations: arkts.AnnotationUsage[] = node.annotations.filter( - (it) => - !isMemoAnnotation(it, RuntimeNames.ANNOTATION) && - !isMemoAnnotation(it, RuntimeNames.ANNOTATION_INTRINSIC) && - !isMemoAnnotation(it, RuntimeNames.ANNOTATION_ENTRY) && - !isMemoAnnotation(it, RuntimeNames.ANNOTATION_STABLE) + (it) => !isMemoAnnotation(it, RuntimeNames.ANNOTATION) && !isMemoAnnotation(it, RuntimeNames.ANNOTATION_STABLE) ); if (arkts.isEtsParameterExpression(node)) { node.annotations = newAnnotations; @@ -265,9 +267,12 @@ export function isStandaloneArrowFunction(node: arkts.AstNode): node is arkts.Ar if (!arkts.isArrowFunctionExpression(node)) return false; // handling anonymous arrow function call - if (arkts.isCallExpression(node.parent) && node.parent.expression.peer === node.peer) return true; + if (!!node.parent && arkts.isCallExpression(node.parent) && node.parent.expression.peer === node.peer) { + return true; + } return ( + !!node.parent && !arkts.isVariableDeclarator(node.parent) && !arkts.isClassProperty(node.parent) && !(arkts.isCallExpression(node.parent) && node.parent.expression) @@ -387,7 +392,7 @@ export function isMemoVariableDeclarator(node: arkts.VariableDeclarator): boolea if (!!node.initializer && arkts.isArrowFunctionExpression(node.initializer)) { isMemo ||= isMemoArrowFunction(node.initializer); } - if (arkts.isVariableDeclaration(node.parent)) { + if (!!node.parent && arkts.isVariableDeclaration(node.parent)) { isMemo ||= isMemoVariableDeclaration(node.parent); } return isMemo; @@ -415,7 +420,7 @@ export function isMemoDeclaredMethod(decl: arkts.MethodDefinition): boolean { ) { return true; } - return isMemoMethodDefinition(decl); + return !hasMemoEntryAnnotation(decl.scriptFunction) && isMemoMethodDefinition(decl); } export function isDeclaredMethodWithMemoParams(decl: arkts.MethodDefinition): boolean { @@ -431,7 +436,7 @@ export function isMemoDeclaredIdentifier(decl: arkts.Identifier): boolean { if (findMemoFromTypeAnnotation(decl.typeAnnotation)) { return true; } - if (arkts.isVariableDeclarator(decl.parent)) { + if (!!decl.parent && arkts.isVariableDeclarator(decl.parent)) { return isMemoVariableDeclarator(decl.parent); } return false; @@ -484,7 +489,7 @@ export function findReturnTypeFromTypeAnnotation( export function getDeclResolveAlias(node: arkts.AstNode): arkts.AstNode | undefined { const decl = arkts.getDecl(node); - if (!!decl && arkts.isIdentifier(decl) && arkts.isVariableDeclarator(decl.parent)) { + if (!!decl && !!decl.parent && arkts.isIdentifier(decl) && arkts.isVariableDeclarator(decl.parent)) { if (!!decl.parent.initializer && arkts.isIdentifier(decl.parent.initializer)) { return getDeclResolveAlias(decl.parent.initializer); } @@ -552,8 +557,10 @@ export function buildReturnTypeInfo( export function buildeParamInfos(parameters: readonly arkts.ETSParameterExpression[]): ParamInfo[] { return [ - ...parameters.map((it) => { - return { ident: it.identifier, param: it }; - }), + ...parameters + .filter((it) => !hasMemoSkipAnnotation(it)) + .map((it) => { + return { ident: it.identifier, param: it }; + }), ]; } diff --git a/arkui-plugins/package.json b/arkui-plugins/package.json index 0267fb00d..75420af81 100644 --- a/arkui-plugins/package.json +++ b/arkui-plugins/package.json @@ -12,7 +12,8 @@ "compile:clean": "rm -rf lib", "clean:test": "rm -rf dist && rm -rf coverage", "prepare:test": "cp -rf $INIT_CWD/../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/koala-wrapper/build/native/ ../koala-wrapper/build/", - "test": "npm run clean:test && npm run prepare:test && LD_LIBRARY_PATH=$INIT_CWD/../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib jest --coverage --logHeapUsage --config ./jest-test.config.js --silent", + "test": "npm run clean:test && npm run prepare:test && LD_LIBRARY_PATH=$INIT_CWD/../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib jest --coverage --logHeapUsage --config ./jest-test.config.js --maxWorkers=25% --silent", + "test:gdb": "LD_LIBRARY_PATH=$INIT_CWD/../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib gdb --args node ./node_modules/.bin/jest --config ./jest-test.config.js", "compile": "npm run compile:clean && npm run compile:plugins && cp -rf ./lib $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ui-plugins/" }, "devDependencies": { diff --git a/arkui-plugins/test/demo/localtest/build_config_template.json b/arkui-plugins/test/demo/localtest/build_config_template.json index 3855891d1..0df152f9d 100755 --- a/arkui-plugins/test/demo/localtest/build_config_template.json +++ b/arkui-plugins/test/demo/localtest/build_config_template.json @@ -1,6 +1,5 @@ { "plugins": { - "ui-syntax-plugin": "workspace/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ui-plugins/lib/ui-syntax-plugins/index", "ui_plugin": "workspace/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ui-plugins/lib/ui-plugins/index", "memo_plugin": "workspace/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ui-plugins/lib/memo-plugins/index" }, @@ -9,7 +8,13 @@ "./demo/localtest/entry/new.ets" ], + "entryFiles": [ + "./demo/localtest/entry/new.ets" + ], + "packageName" : "entry", + "moduleType": "shared", + "hasMainModule": true, "buildType": "build", "buildMode": "Debug", diff --git a/arkui-plugins/test/demo/localtest/entry/new.ets b/arkui-plugins/test/demo/localtest/entry/new.ets index acdb7c3c3..a66597507 100755 --- a/arkui-plugins/test/demo/localtest/entry/new.ets +++ b/arkui-plugins/test/demo/localtest/entry/new.ets @@ -13,60 +13,62 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" // should be insert by ui-plugins -import { Text, TextAttribute, Column, Component, Button, ButtonAttribute, ClickEvent, UserView } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins -import { State, Link, StateDecoratedVariable, LinkDecoratedVariable,MutableState, stateOf, observableProxy } from "@ohos.arkui.stateManagement" // should be insert by ui-plugins +import { Text, Column, Component, Entry, Button, ClickEvent } from "@ohos.arkui.component" +import { State, Link, Prop } from "@ohos.arkui.stateManagement" import hilog from '@ohos.hilog' -function ArkUICompatible(init:(elmtId: number, instance: ESObject) => void, update: ((elmtId: number, instance: ESObject) => void)) { - -} - +@Entry @Component struct MyStateSample { - @State stateVar: string = "Parent"; - message: string = "var"; + @State stateVar: string = "state var"; + message: string = `click to change state variable, add **`; changeValue() { - this.stateVar+="~"; + this.stateVar+="**" } build() { - Column(undefined) { - Button("ParentChange").backgroundColor("#FFFF00FF") + Column() { + Button("clean variable").onClick((e: ClickEvent) => { this.stateVar = "state var" }) + Text("Hello World").fontSize(20) + Button(this.message).backgroundColor("#FFFF00FF") .onClick((e: ClickEvent) => { hilog.info(0x0000, 'testTag', 'On Click'); - this.changeValue(); + this.changeValue() }) Text(this.stateVar).fontSize(20) - ChildLink({stateVar: this.stateVar, stateVar1: this.stateVar, stateVar2: ""} as __Options_ChildLink) - } + Child({linkVar: this.stateVar, propVar: this.stateVar}) + }.margin(10) } } @Component -struct ChildLink { - @Link stateVar: string = "Child"; - @State stateVar1: string = "Child"; - @Link stateVar2: string = "Child"; - changeValue() { - this.stateVar+="~"; +struct Child { + @Link linkVar: string = ""; // TODO: remove this + @Prop propVar: string = "Prop"; + + changeValue1() { + this.linkVar+="!!" } - build() { - Button("ChildChange").backgroundColor("#FFFF00FF") - .onClick((e: ClickEvent) => { - hilog.info(0x0000, 'testTag', 'On Click'); - this.changeValue(); - }) - Text(this.stateVar).fontSize(50) + + changeValue2() { + this.propVar+="~~" } -} -export class ComExampleTrivialApplication extends UserView { - getBuilder() { - hilog.info(0x0000, 'testTag', 'getBuilder'); - let wrapper = @memo () => { - hilog.info(0x0000, 'testTag', 'MyStateSample'); - MyStateSample(undefined); + build() { + Column() { + Button(`click to change Link variable, add symbol !!`) + .backgroundColor("#4169E1") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + this.changeValue1() + }) + Button(`click to change Prop variable, add symbol ~~`) + .backgroundColor("#3CB371") + .onClick((e: ClickEvent) => { + hilog.info(0x0000, 'testTag', 'On Click'); + this.changeValue2() + }) + Text(`Link variable in child: ${this.linkVar}`).fontSize(30) + Text(`Prop variable in child: ${this.propVar}`).fontSize(30) } - return wrapper; } } \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/builder-lambda/simple-component.ets b/arkui-plugins/test/demo/mock/builder-lambda/simple-component.ets index 4f0f3b5cf..50ef19686 100644 --- a/arkui-plugins/test/demo/mock/builder-lambda/simple-component.ets +++ b/arkui-plugins/test/demo/mock/builder-lambda/simple-component.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" import { Column, UIColumnAttribute } from "arkui.component.column" class MyStateSample { diff --git a/arkui-plugins/test/local/@ohos.arkui.external.resource.d.ets b/arkui-plugins/test/demo/mock/common-utils/annotation.ets similarity index 66% rename from arkui-plugins/test/local/@ohos.arkui.external.resource.d.ets rename to arkui-plugins/test/demo/mock/common-utils/annotation.ets index 9cc3b09e0..e8a78a587 100644 --- a/arkui-plugins/test/local/@ohos.arkui.external.resource.d.ets +++ b/arkui-plugins/test/demo/mock/common-utils/annotation.ets @@ -1,5 +1,5 @@ /* - * Copyright (C) 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 @@ -13,4 +13,20 @@ * limitations under the License. */ -export type Resource = boolean; \ No newline at end of file +@Retention({policy:"SOURCE"}) @interface TestAnno {} + +type TestType = number; + +() => {}; + +class A { + prop: number = 1; + + method(arg1: number): void { + const a: number = arg1; + } +} + +interface __A { + prop: number; +} \ No newline at end of file diff --git a/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets b/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets index 54263a552..acb0c7d65 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo function memo_arg_call( arg1: number, diff --git a/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets b/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets index ac8324d22..8d11b8eeb 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/declare-and-call.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo declare function funcA(): void; diff --git a/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets b/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets index 313164b28..ceddf1eea 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/inner-functions.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo function foo() { } diff --git a/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets b/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets index cc0f993ec..0e2efd774 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/non-void-return-type.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo function funcNum(): number { diff --git a/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets b/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets index be715df95..d8b38e410 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/type-reference.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo type ItemBuilder = (item: Item) => void; diff --git a/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets b/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets index 840c84aaf..7ac6d38e6 100644 --- a/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets +++ b/arkui-plugins/test/demo/mock/memo/functions/void-return-type.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo function func(): void { diff --git a/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets b/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets index def28807a..c84028318 100644 --- a/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets +++ b/arkui-plugins/test/demo/mock/memo/lambdas/argument-call.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" (arg: (()=>void)) => {}(() => {}); diff --git a/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets b/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets index 08d252f58..46ac5cacf 100644 --- a/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets +++ b/arkui-plugins/test/demo/mock/memo/lambdas/trailing-lambdas.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" class A { @memo foo(p?: ()=>void): void {} diff --git a/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets b/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets index fb757d8b6..b1b80a22c 100644 --- a/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets +++ b/arkui-plugins/test/demo/mock/memo/lambdas/void-lambda.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" @memo (): void => { diff --git a/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets b/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets index b54c9c6c2..424e210ff 100644 --- a/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets +++ b/arkui-plugins/test/demo/mock/memo/lambdas/with-receiver.ets @@ -13,7 +13,7 @@ * limitations under the License. */ - import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" + import { memo } from "@ohos.arkui.stateManagement" class Person { constructor() {} diff --git a/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets b/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets index 5f799140f..08bcf33c0 100644 --- a/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets +++ b/arkui-plugins/test/demo/mock/memo/methods/argument-call.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" class Test { @memo lambda_arg(@memo arg: () => void) { diff --git a/arkui-plugins/test/demo/mock/memo/methods/callable.ets b/arkui-plugins/test/demo/mock/memo/methods/callable.ets index 2f4e2a401..2b058b77c 100644 --- a/arkui-plugins/test/demo/mock/memo/methods/callable.ets +++ b/arkui-plugins/test/demo/mock/memo/methods/callable.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" class A { @memo diff --git a/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets b/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets index e28c85361..432d79624 100644 --- a/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets +++ b/arkui-plugins/test/demo/mock/memo/methods/declare-and-call.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" declare abstract class A { @memo diff --git a/arkui-plugins/test/demo/mock/memo/methods/void-method.ets b/arkui-plugins/test/demo/mock/memo/methods/void-method.ets index ed3339dd1..e96c07df2 100644 --- a/arkui-plugins/test/demo/mock/memo/methods/void-method.ets +++ b/arkui-plugins/test/demo/mock/memo/methods/void-method.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" class A { x: int diff --git a/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets b/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets index 725d2702b..720a1df76 100644 --- a/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets +++ b/arkui-plugins/test/demo/mock/memo/properties/class-constructor.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" interface A { @memo a: () => void diff --git a/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets b/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets index 9fe1e5dc4..309dbd6c3 100644 --- a/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets +++ b/arkui-plugins/test/demo/mock/memo/properties/class-properties.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" class A { arg: () => void diff --git a/arkui-plugins/test/demo/mock/memo/properties/implements.ets b/arkui-plugins/test/demo/mock/memo/properties/implements.ets index ad61b2a7a..50d691226 100644 --- a/arkui-plugins/test/demo/mock/memo/properties/implements.ets +++ b/arkui-plugins/test/demo/mock/memo/properties/implements.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" interface A { @memo prop: (() => void) | undefined diff --git a/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets b/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets index c46a181e5..d7fa93fb3 100644 --- a/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets +++ b/arkui-plugins/test/demo/mock/memo/properties/interfaces.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -import { memo, __memo_context_type, __memo_id_type } from "@ohos.arkui.stateManagement" +import { memo } from "@ohos.arkui.stateManagement" interface A { arg: () => void diff --git a/arkui-plugins/test/local/@ohos.arkui.component.customComponent.d.ets b/arkui-plugins/test/local/@ohos.arkui.component.customComponent.d.ets deleted file mode 100644 index 728c949e7..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.component.customComponent.d.ets +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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 "@ohos.arkui.stateManagement.runtime"; -import { ComponentBuilder, CommonMethod } from "@ohos.arkui.component.common"; -import { Length, ResourceColor } from "@ohos.arkui.component.units"; - -@Retention({policy: "SOURCE"}) -export declare @interface Component {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Entry { routeName: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface Reusable {}; - -export declare abstract class CustomComponent, T_Options> implements - CommonMethod { - - @memo - @ComponentBuilder - static $_instantiate, S_Options>( - factory: () => S, - initializers?: S_Options, - @memo - content?: () => void - ): S; - - // Life cycle for custom component - aboutToAppear(): void; - aboutToDisappear(): void; - aboutToReuse(): void; - aboutToRecycle(): void; - - @memo - build(): void; - - // Implementation of common method - @memo - width(w: Length): this; - @memo - height(h: Length): this; - @memo - backgroundColor(color: ResourceColor): this; -} \ No newline at end of file diff --git a/arkui-plugins/test/local/@ohos.arkui.component.styledString.d.ets b/arkui-plugins/test/local/@ohos.arkui.component.styledString.d.ets deleted file mode 100644 index 4a0e94d6f..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.component.styledString.d.ets +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 declare class StyledString { - constructor(value: string /*| ImageAttachment | CustomSpan, styles?: Array*/); - - readonly length: number; - - getString(): string; - // getStyles(start: number, length: number, styledKey?: StyledStringKey): Array; - equals(other: StyledString): boolean; - subStyledString(start: number, length?: number): StyledString; - - static fromHtml(html: string): Promise; - static toHtml(styledString: StyledString): string; - // static marshalling(styledString: StyledString, callback: StyledStringMarshallCallback): ArrayBuffer; - // static unmarshalling(buffer: ArrayBuffer, callback: StyledStringUnmarshallCallback): Promise; - // static marshalling(styledString: StyledString): ArrayBuffer; - // static unmarshalling(buffer: ArrayBuffer): Promise; -} \ No newline at end of file diff --git a/arkui-plugins/test/local/@ohos.arkui.component.text.d.ets b/arkui-plugins/test/local/@ohos.arkui.component.text.d.ets deleted file mode 100644 index 5ba7ef754..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.component.text.d.ets +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Resource } from "@ohos.arkui.external.resource"; -import { StyledString } from "@ohos.arkui.component.styledString"; -import { ComponentBuilder, CommonMethod } from "@ohos.arkui.component.common"; -import { ResourceColor, Length } from "@ohos.arkui.component.units"; -import { memo } from '@ohos.arkui.stateManagement.runtime'; - -export declare class TextController { - closeSelectionMenu(): void; - setStyledString(value: StyledString): void; - - // getLayoutManager(): LayoutManager; -} - -export declare interface TextOptions { - controller: TextController; -} - -export declare interface TextAttribute extends CommonMethod { - // @memo - // font(value: Font, options?: FontSettingOptions): this; - @memo - fontColor(value: ResourceColor): this; - @memo - fontSize(value: number | string | Resource): this; - @memo - minFontSize(value: number | string | Resource): this; - @memo - maxFontSize(value: number | string | Resource): this; - @memo - minFontScale(scale: number | Resource): this; - @memo - maxFontScale(scale: number | Resource): this; - // @memo - // fontStyle(value: FontStyle): this; - // @memo - // fontWeight(value: number | FontWeight | string): this; - // @memo - // fontWeight(weight: number | FontWeight | string, options?: FontSettingOptions): this; - // @memo - // lineSpacing(value: LengthMetrics): this; - // @memo - // textAlign(value: TextAlign): this; - @memo - lineHeight(value: number | string | Resource): this; - // @memo - // textOverflow(options: TextOverflowOptions): this; - @memo - fontFamily(value: string | Resource): this; - @memo - maxLines(value: number): this; - // @memo - // decoration(value: DecorationStyleInterface): this; - @memo - letterSpacing(value: number | string): this; - // @memo - // textCase(value: TextCase): this; - @memo - baselineOffset(value: number | string): this; - // @memo - // copyOption(value: CopyOptions): this; - @memo - draggable(value: boolean): this; - // @memo - // textShadow(value: ShadowOptions | Array): this; - // @memo - // heightAdaptivePolicy(value: TextHeightAdaptivePolicy): this; - @memo - textIndent(value: Length): this; - // @memo - // wordBreak(value: WordBreak): this; - // @memo - // lineBreakStrategy(strategy: LineBreakStrategy): this; - @memo - onCopy(callback: (value: string) => void): this; - @memo - selection(selectionStart: number, selectionEnd: number): this; - @memo - caretColor(color: ResourceColor): this; - @memo - selectedBackgroundColor(color: ResourceColor): this; - // @memo - // ellipsisMode(value: EllipsisMode): this; - @memo - enableDataDetector(enable: boolean): this; - // @memo - // dataDetectorConfig(config: TextDataDetectorConfig): this; - // @memo - // bindSelectionMenu(spanType: TextSpanType, content: CustomBuilder, responseType: TextResponseType, - // options?: SelectionMenuOptions): this; - @memo - onTextSelectionChange(callback: (selectionStart: number, selectionEnd: number) => void): this; - @memo - fontFeature(value: string): this; - // @memo - // marqueeOptions(options: Optional): this; - // @memo - // onMarqueeStateChange(callback: Callback): this; - @memo - privacySensitive(supported: boolean): this; - // @memo - // textSelectable(mode: TextSelectableMode): this; - // @memo - // editMenuOptions(editMenu: EditMenuOptions): this; - @memo - halfLeading(halfLeading: boolean): this; - @memo - enableHapticFeedback(isEnabled: boolean): this; -} - -@memo -@ComponentBuilder -export declare function Text ( - value?: string | Resource, - options?: TextOptions, - @memo - content?: () => void -): TextAttribute; diff --git a/arkui-plugins/test/local/@ohos.arkui.stateManagement.common.d.ets b/arkui-plugins/test/local/@ohos.arkui.stateManagement.common.d.ets deleted file mode 100644 index 274947957..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.stateManagement.common.d.ets +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@Retention({policy: "SOURCE"}) -export declare @interface State {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Prop {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Link {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Observed {}; - -@Retention({policy: "SOURCE"}) -export declare @interface Track {}; - -@Retention({policy: "SOURCE"}) -export declare @interface ObjectLink {}; - -@Retention({policy: "SOURCE"}) -export declare @interface StorageProp { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface StorageLink { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface LocalStorageProp { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface LocalStorageLink { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface Provide { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface Consume { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface Watch { value: string }; - -@Retention({policy: "SOURCE"}) -export declare @interface Require {}; - -export declare class UIUtils { - static getTarget(source: T): T; - static makeObserved(source: T): T; -} \ No newline at end of file diff --git a/arkui-plugins/test/local/@ohos.arkui.stateManagement.runtime.d.ets b/arkui-plugins/test/local/@ohos.arkui.stateManagement.runtime.d.ets deleted file mode 100644 index f70c0cb7f..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.stateManagement.runtime.d.ets +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocalStorage } from "@ohos.arkui.stateManagement.storage" - -// From incremental engine -@Retention({policy: "SOURCE"}) -export declare @interface memo {}; - -export type __memo_context_type = StateContext; -export type __memo_id_type = MemoCallSiteKey; - -export type MemoCallSiteKey = int; - -export declare interface Disposable { - readonly disposed: boolean; - dispose(): void; -} - -export declare interface State { - readonly modified: boolean; - readonly value: T; -} - -export declare interface MutableState extends Disposable, State { - value: T; -} - -export type Equivalent = (oldV: T, newV: T) => boolean; - -export declare interface InternalScope { - readonly unchanged: boolean; - readonly cached: Value; - recache(newValue?: Value): Value; - param(index: int, value: T, equivalent?: Equivalent, name?: string, contextLocal?: boolean): State; -} - -export declare interface StateContext { - scope(id: MemoCallSiteKey, paramCount?: int): InternalScope; -} - -// From Arkoala -export declare function propState(value?: T): MutableState; -export declare function objectLinkState(value?: T): MutableState; -export declare function stateOf(value: T): MutableState; -export declare function contextLocalStateOf(value: T, key: () => T): MutableState; -export declare function contextLocal(value: T): MutableState; -export declare function observableProxy(value: T): T; -export declare function StorageLinkState(storage: LocalStorage, name: string, value: T): MutableState -export declare function AppStorageLinkState(name: string, value: T): MutableState; \ No newline at end of file diff --git a/arkui-plugins/test/local/@ohos.arkui.stateManagement.storage.d.ets b/arkui-plugins/test/local/@ohos.arkui.stateManagement.storage.d.ets deleted file mode 100644 index a7257c839..000000000 --- a/arkui-plugins/test/local/@ohos.arkui.stateManagement.storage.d.ets +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 declare interface StorageProperty { - key: string; - defaultValue: number | string | boolean | Object; -} - -export type PersistPropsOptions = StorageProperty; - -export declare interface AbstractProperty { - info(): string; - get(): T; - set(newValue: T): void; -} - -export declare interface SubscribedAbstractProperty extends AbstractProperty { - aboutToBeDeleted(): void; -} - -export declare class LocalStorage { - static getShared(): LocalStorage | undefined; - - constructor(initializingProperties?: StorageProperty[]); - - has(propName: string): boolean; - - keys(): IterableIterator; - - size(): int; - - get(propName: string): T | undefined; - - set(propName: string, newValue: T): boolean; - - setOrCreate(propName: string, newValue?: T): boolean; - - ref(propName: string): AbstractProperty | undefined; - - setAndRef(propName: string, defaultValue: T): AbstractProperty; - - link(propName: string): SubscribedAbstractProperty | undefined; - - setAndLink(propName: string, defaultValue: T): SubscribedAbstractProperty; - - prop(propName: string): SubscribedAbstractProperty | undefined; - - setAndProp(propName: string, defaultValue: T): SubscribedAbstractProperty; - - delete(propName: string): boolean; - - clear(): boolean; -} - -export declare class AppStorage { - static has(propName: string): boolean; - - static keys(): IterableIterator; - - static size(): int; - - static get(propName: string): T | undefined; - - static set(propName: string, newValue: T): boolean; - - static setOrCreate(propName: string, newValue?: T): boolean; - - static ref(propName: string): AbstractProperty | undefined; - - static setAndRef(propName: string, defaultValue: T): AbstractProperty; - - static link(propName: string): SubscribedAbstractProperty | undefined; - - static setAndLink(propName: string, defaultValue: T): SubscribedAbstractProperty; - - static prop(propName: string): SubscribedAbstractProperty | undefined; - - static setAndProp(propName: string, defaultValue: T): SubscribedAbstractProperty; - - static delete(propName: string): boolean; - - static clear(): boolean; -} - -export declare class PersistentStorage { - - static persistProp(key: string, defaultValue: T): void; - - static deleteProp(key: string): void; - - static persistProps(props: PersistPropsOptions[]): void; - - static keys(): Array; -} - -export declare interface EnvPropsOptions { - key: string; - defaultValue: number | string | boolean; -} - -export declare class Environment { - static envProp(key: string, value: S): boolean; - - static envProps(props: EnvPropsOptions[]): void; - - static keys(): Array; -} \ No newline at end of file diff --git a/arkui-plugins/test/package.json b/arkui-plugins/test/package.json index 07123fbd7..34fcd06f2 100644 --- a/arkui-plugins/test/package.json +++ b/arkui-plugins/test/package.json @@ -11,6 +11,7 @@ "clean:test": "rm -rf generated", "clean:all": "npm run clean:localtest && npm run clean:test", "test": "npm run clean:all && npm run compile:plugins && cd .. && npm run test", + "test:gdb": "npm run clean:all && npm run compile:plugins && cd .. && npm run test:gdb", "localtest": "rm -rf dist && node localtest_config.js && npm run compile:plugins && LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_config.json", "localtest_gdb": "LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib gdb --args node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_config.json", "localtest_decl": "rm -rf dist && node localtest_decl_config.js && npm run compile:plugins && LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_decl_config.json", diff --git a/arkui-plugins/test/test.log b/arkui-plugins/test/test.log deleted file mode 100644 index 984a29adf..000000000 --- a/arkui-plugins/test/test.log +++ /dev/null @@ -1,372 +0,0 @@ - -> build_system_test@1.0.0 compile:ohos_sdk -> node /home/wuhaibin/newcode/oh/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/hello_world/build_config.json - -[ - '/home/wuhaibin/.nvm/versions/node/v23.8.0/bin/node', - '/home/wuhaibin/newcode/oh/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js', - './demo/hello_world/build_config.json' -] -Updated PATH: /home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/arkui-plugins/test/node_modules/.bin:/home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/arkui-plugins/node_modules/.bin:/home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/node_modules/.bin:/home/wuhaibin/newcode/oh/developtools/node_modules/.bin:/home/wuhaibin/newcode/oh/node_modules/.bin:/home/wuhaibin/newcode/node_modules/.bin:/home/wuhaibin/node_modules/.bin:/home/node_modules/.bin:/node_modules/.bin:/home/wuhaibin/.nvm/versions/node/v23.8.0/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin:/home/wuhaibin/.local/bin:/home/wuhaibin/bin:/home/wuhaibin/.nvm/versions/node/v23.8.0/bin:/home/wuhaibin/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Users/wuhaibin/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/wuhaibin/AppData/Local/Programs/Microsoft VS Code/bin:/snap/bin:/home/wuhaibin/newcode/oh/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib -Loaded plugin: ui-plugin { uiTransform: [Function: uiTransform] } [Function: uiTransform] -Loaded plugin: memo-plugin { unmemoizeTransform: [Function: unmemoizeTransform] } [Function: unmemoizeTransform] -ets2pandaCmd: _ --extension ets --arktsconfig /home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/arkui-plugins/test/dist/cache/entry/arktsconfig.json --output /home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/arkui-plugins/test/dist/cache/entry/a.abc --debug-info ./demo/hello_world/entry/a.ets -[TS WRAPPER] CREATE CONFIG -InitModule: es2panda - -[TS WRAPPER] PROCEED TO STATE: 1 -es2panda proceedToState parsed -[TS WRAPPER] GET AST FROM CONTEXT -executing plugin: ui-plugin -[UI PLUGIN] AFTER PARSED ENTER -[AFTER PARSED SCRIPT]: -import { StructBase } from "@koalaui.arkts-arkui.StructBase"; - -import { Text as Text } from "@koalaui.arkts-arkui.Text"; - -import { Column as Column } from "@koalaui.arkts-arkui.Column"; - -import { Button as Button } from "@koalaui.arkts-arkui.Button"; - -import { Component as Component, StorageLink as StorageLink, State as State } from "@koalaui.arkts-arkui.Common"; - -import { UserView as UserView, UserViewBuilder as UserViewBuilder } from "@koalaui.arkts-arkui.UserView"; - -import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "@ohos.arkui.StateManagement.runtime"; - -import { memo as memo } from "@ohos.arkui.StateManagement.runtime"; - -function isTrue(): string { - return "aa"; -} - -final class MyStateSample extends StructBase { - public aaa: string = isTrue(); - - public build() { - Column(){ - Text("Hello World!"); - Text((this).aaa); - Button("change"); - }; - } - - public constructor() {} - -} - -class ComExampleTrivialApplication extends UserView { - public getBuilder(): UserViewBuilder { - let wrapper = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - MyStateSample.instantiateImpl(undefined, ((): MyStateSample => new MyStateSample()), ({} as __Options_MyStateSample), undefined); - }); - return wrapper; - } - - public constructor() {} - -} - -interface __Options_MyStateSample { - -} - - -[UI PLUGIN] AFTER PARSED EXIT -plugin parsed finished -[TS WRAPPER] GET AST FROM CONTEXT -[TS WRAPPER] DESTROY AND RECREATE -[TS WRAPPER] PROCEED TO STATE: 4 -es2panda proceedToState checked -[TS WRAPPER] GET AST FROM CONTEXT -executing plugin: ui-plugin -[UI PLUGIN] AFTER CHECKED ENTER -[AFTER STRUCT SCRIPT] script: -import { StructBase as StructBase } from "@koalaui.arkts-arkui.StructBase"; - -import { Text as Text } from "@koalaui.arkts-arkui.Text"; - -import { Column as Column } from "@koalaui.arkts-arkui.Column"; - -import { Button as Button } from "@koalaui.arkts-arkui.Button"; - -import { Component as Component, StorageLink as StorageLink, State as State } from "@koalaui.arkts-arkui.Common"; - -import { UserView as UserView, UserViewBuilder as UserViewBuilder } from "@koalaui.arkts-arkui.UserView"; - -import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "@ohos.arkui.StateManagement.runtime"; - -import { memo as memo } from "@ohos.arkui.StateManagement.runtime"; - -abstract class ETSGLOBAL { - public static main() {} - - public static _$init$_() {} - - public static isTrue(): string { - return "aa"; - } - - -} - -class MyStateSample extends StructBase { - @memo()public __initializeStruct(initializers?: __Options_MyStateSample, @memo()content?: (()=> void)): void {} - - public __updateStruct(initializers: __Options_MyStateSample | undefined): void {} - - public aaa: string = ETSGLOBAL.isTrue(); - - @memo()protected _build(@memo()style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo()content: (()=> void) | undefined, initializers?: __Options_MyStateSample): void { - Column.instantiateImpl(((instance: Column): Column => { - return instance; - }), ((): Column => { - return new Column(); - }), (() => { - Text.instantiateImpl(((instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), "Hello World!") - Text.instantiateImpl(((instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), (this).aaa) - Button.instantiateImpl(((instance: Button): Button => { - return instance; - }), ((): Button => { - return new Button(); - }), "change") - })); - } - - public constructor() {} - -} - -class ComExampleTrivialApplication extends UserView { - public getBuilder(): UserViewBuilder { - let wrapper = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - MyStateSample.instantiateImpl(undefined, ((): MyStateSample => { - return new MyStateSample(); - }), ({} as __Options_MyStateSample), undefined); - }); - return wrapper; - } - - public constructor() {} - -} - -interface __Options_MyStateSample { - -} - - -[UI PLUGIN] AFTER CHECKED EXIT -executing plugin: memo-plugin -[MEMO PLUGIN] AFTER CHECKED ENTER -[BEFORE MEMO SCRIPT] script: -import { StructBase as StructBase } from "@koalaui.arkts-arkui.StructBase"; - -import { Text as Text } from "@koalaui.arkts-arkui.Text"; - -import { Column as Column } from "@koalaui.arkts-arkui.Column"; - -import { Button as Button } from "@koalaui.arkts-arkui.Button"; - -import { Component as Component, StorageLink as StorageLink, State as State } from "@koalaui.arkts-arkui.Common"; - -import { UserView as UserView, UserViewBuilder as UserViewBuilder } from "@koalaui.arkts-arkui.UserView"; - -import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "@ohos.arkui.StateManagement.runtime"; - -import { memo as memo } from "@ohos.arkui.StateManagement.runtime"; - -abstract class ETSGLOBAL { - public static main() {} - - public static _$init$_() {} - - public static isTrue(): string { - return "aa"; - } - - -} - -class MyStateSample extends StructBase { - @memo()public __initializeStruct(initializers?: __Options_MyStateSample, @memo()content?: (()=> void)): void {} - - public __updateStruct(initializers: __Options_MyStateSample | undefined): void {} - - public aaa: string = ETSGLOBAL.isTrue(); - - @memo()protected _build(@memo()style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo()content: (()=> void) | undefined, initializers?: __Options_MyStateSample): void { - Column.instantiateImpl(((instance: Column): Column => { - return instance; - }), ((): Column => { - return new Column(); - }), (() => { - Text.instantiateImpl(((instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), "Hello World!") - Text.instantiateImpl(((instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), (this).aaa) - Button.instantiateImpl(((instance: Button): Button => { - return instance; - }), ((): Button => { - return new Button(); - }), "change") - })); - } - - public constructor() {} - -} - -class ComExampleTrivialApplication extends UserView { - public getBuilder(): UserViewBuilder { - let wrapper = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - MyStateSample.instantiateImpl(undefined, ((): MyStateSample => { - return new MyStateSample(); - }), ({} as __Options_MyStateSample), undefined); - }); - return wrapper; - } - - public constructor() {} - -} - -interface __Options_MyStateSample { - -} - - -[AFTER MEMO SCRIPT] script: -import { StructBase as StructBase } from "@koalaui.arkts-arkui.StructBase"; - -import { Text as Text } from "@koalaui.arkts-arkui.Text"; - -import { Column as Column } from "@koalaui.arkts-arkui.Column"; - -import { Button as Button } from "@koalaui.arkts-arkui.Button"; - -import { Component as Component, StorageLink as StorageLink, State as State } from "@koalaui.arkts-arkui.Common"; - -import { UserView as UserView, UserViewBuilder as UserViewBuilder } from "@koalaui.arkts-arkui.UserView"; - -import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "@ohos.arkui.StateManagement.runtime"; - -import { memo as memo } from "@ohos.arkui.StateManagement.runtime"; - -abstract class ETSGLOBAL { - public static main() {} - - public static _$init$_() {} - - public static isTrue(): string { - return "aa"; - } - - -} - -class MyStateSample extends StructBase { - public __initializeStruct(__memo_context: __memo_context_type, __memo_id: __memo_id_type, initializers?: __Options_MyStateSample, content?: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void)): void { - const __memo_scope = __memo_context.scope(((__memo_id) + (168924120)), 2); - const __memo_parameter_initializers = __memo_scope.param(0, initializers), __memo_parameter_content = __memo_scope.param(1, content); - if (__memo_scope.unchanged) { - __memo_scope.recache(__memo_scope.cached) - return; - } - { - __memo_scope.recache() - return; - } - } - - public __updateStruct(initializers: __Options_MyStateSample | undefined): void {} - - public aaa: string = ETSGLOBAL.isTrue(); - - protected _build(__memo_context: __memo_context_type, __memo_id: __memo_id_type, style: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: MyStateSample)=> MyStateSample) | undefined, content: ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void) | undefined, initializers?: __Options_MyStateSample): void { - const __memo_scope = __memo_context.scope(((__memo_id) + (168198604)), 3); - const __memo_parameter_style = __memo_scope.param(0, style), __memo_parameter_content = __memo_scope.param(1, content), __memo_parameter_initializers = __memo_scope.param(2, initializers); - if (__memo_scope.unchanged) { - __memo_scope.recache(__memo_scope.cached) - return; - } - Column.instantiateImpl(__memo_context, ((__memo_id) + (229216764)), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: Column): Column => { - return instance; - }), ((): Column => { - return new Column(); - }), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - const __memo_scope = __memo_context.scope(((__memo_id) + (131080140)), 0); - if (__memo_scope.unchanged) { - __memo_scope.recache(__memo_scope.cached) - return; - } - Text.instantiateImpl(__memo_context, ((__memo_id) + (122349231)), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), "Hello World!") - Text.instantiateImpl(__memo_context, ((__memo_id) + (259830593)), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: Text): Text => { - return instance; - }), ((): Text => { - return new Text(); - }), (this).aaa) - Button.instantiateImpl(__memo_context, ((__memo_id) + (23671947)), ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, instance: Button): Button => { - return instance; - }), ((): Button => { - return new Button(); - }), "change") - { - __memo_scope.recache() - return; - } - })); - { - __memo_scope.recache() - return; - } - } - - public constructor() {} - -} - -class ComExampleTrivialApplication extends UserView { - public getBuilder(): UserViewBuilder { - let wrapper = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type) => { - MyStateSample.instantiateImpl(__memo_context, ((__memo_id) + (44218244)), undefined, ((): MyStateSample => { - return new MyStateSample(); - }), ({} as __Options_MyStateSample), undefined); - }); - return wrapper; - } - - public constructor() {} - -} - -interface __Options_MyStateSample { - -} - - -[MEMO PLUGIN] AFTER CHECKED EXIT -plugin checked finished -[TS WRAPPER] GET AST FROM CONTEXT -[TS WRAPPER] DESTROY AND RECREATE -[TS WRAPPER] PROCEED TO STATE: 7 -es2panda bin generated -"/home/wuhaibin/newcode/oh/out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/bin/ark_link" --output "/home/wuhaibin/newcode/oh/developtools/ace_ets2bundle/arkui-plugins/test/dist/modules_static.abc" -- @"dist/cache/fileInfo.txt" diff --git a/arkui-plugins/test/ut/common/annotation.test.ts b/arkui-plugins/test/ut/common/annotation.test.ts index cf9f7d191..d7640d7af 100644 --- a/arkui-plugins/test/ut/common/annotation.test.ts +++ b/arkui-plugins/test/ut/common/annotation.test.ts @@ -13,24 +13,195 @@ * limitations under the License. */ -import { PluginTestContext, PluginTester } from '../../utils/plugin-tester'; -import { annotation } from '../../../common/arkts-utils'; import * as arkts from '@koalaui/libarkts'; +import path from 'path'; +import { PluginTester } from '../../utils/plugin-tester'; +import { BuildConfig, PluginTestContext } from '../../utils/shared-types'; +import { recheck } from '../../utils/plugins'; +import { mockBuildConfig } from '../../utils/artkts-config'; +import { parseDumpSrc } from '../../utils/parse-string'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../utils/path-config'; +import { annotation } from '../../../common/arkts-utils'; +import { PluginContext, Plugins } from '../../../common/plugin-context'; +import { AbstractVisitor } from '../../../common/abstract-visitor'; + +const COMMON_UTILS_DIR_PATH: string = 'common-utils'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, COMMON_UTILS_DIR_PATH, 'annotation.ets')]; + +const pluginTester = new PluginTester('test arkts-utils', buildConfig); -const pluginTester = new PluginTester('test arkts-utils'); +type AnnotationAstNode = + | arkts.ClassDefinition + | arkts.ClassProperty + | arkts.ETSParameterExpression + | arkts.ArrowFunctionExpression + | arkts.MethodDefinition + | arkts.VariableDeclaration + | arkts.TSInterfaceDeclaration + | arkts.TSTypeAliasDeclaration; + +class AnnotationVisitor extends AbstractVisitor { + isRemover: boolean; + + constructor(isRemover?: boolean) { + super(); + this.isRemover = !!isRemover; + } + + private testAnnotation(): arkts.AnnotationUsage { + return annotation('TestAnno'); + } + + addTestAnnotation(node: AnnotationAstNode): void { + if (arkts.isEtsParameterExpression(node)) { + node.annotations = [this.testAnnotation()]; + } else if (arkts.isMethodDefinition(node)) { + node.scriptFunction.setAnnotations([this.testAnnotation()]); + node.setOverloads( + node.overloads.map((ov) => { + if (this.isAnnotationNode(ov)) { + this.addTestAnnotation(ov); + } + return ov; + }) + ); + } else { + node.setAnnotations([this.testAnnotation()]); + } + } + + removeTestAnnotation(node: AnnotationAstNode): void { + if (arkts.isEtsParameterExpression(node)) { + node.annotations = []; + } else if (arkts.isMethodDefinition(node)) { + node.scriptFunction.setAnnotations([]); + node.setOverloads( + node.overloads.map((ov) => { + if (this.isAnnotationNode(ov)) { + this.removeTestAnnotation(ov); + } + return ov; + }) + ); + } else { + node.setAnnotations([]); + } + } + + isAnnotationNode(node: arkts.AstNode): node is AnnotationAstNode { + return ( + arkts.isClassDefinition(node) || + arkts.isClassProperty(node) || + arkts.isMethodDefinition(node) || + arkts.isEtsParameterExpression(node) || + arkts.isArrowFunctionExpression(node) || + arkts.isMethodDefinition(node) || + arkts.isVariableDeclaration(node) || + arkts.isTSInterfaceDeclaration(node) || + arkts.isTSTypeAliasDeclaration(node) + ); + } + + visitor(node: arkts.AstNode): arkts.AstNode { + if (this.isAnnotationNode(node)) { + if (this.isRemover) { + this.removeTestAnnotation(node); + } else { + this.addTestAnnotation(node); + } + } + return this.visitEachChild(node); + } +} + +function addAnnotationTransform(this: PluginContext): arkts.EtsScript | undefined { + let script: arkts.EtsScript | undefined; + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + const annotationAdder = new AnnotationVisitor(); + annotationAdder.visitor(program.astNode); + script = program.astNode; + return script; + } + return script; +} + +function removeAnnotationTransform(this: PluginContext): arkts.EtsScript | undefined { + let script: arkts.EtsScript | undefined; + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!!contextPtr) { + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + const annotationAdder = new AnnotationVisitor(true); + annotationAdder.visitor(program.astNode); + script = program.astNode; + return script; + } + return script; +} + +const addAnnotation: Plugins = { + name: 'add-annotation', + parsed: addAnnotationTransform, + checked: addAnnotationTransform, +}; + +const removeAnnotation: Plugins = { + name: 'remove-annotation', + parsed: removeAnnotationTransform, + checked: removeAnnotationTransform, +}; + +const expectedParseSnapshot: string = ` +@Retention({policy:\"SOURCE\"}) @interface TestAnno {} +@TestAnno() type TestType = number; +@TestAnno() (() => {}) +@TestAnno() class A { + @TestAnno() public prop: number = 1; + @TestAnno() public method(@TestAnno() arg1: number): void { + @TestAnno() const a: number = arg1; + } + @TestAnno() public constructor() {} +} +@TestAnno() interface __A { + @TestAnno() prop: number; +} +`; + +function testParseAnnotation(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedParseSnapshot)); +} + +const expectedCheckSnapshot: string = ` +@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() const a: number = arg1; + } + @TestAnno() public constructor() {} +} +@TestAnno() interface __A { + @TestAnno() set prop(prop: number) + @TestAnno() get prop(): number +} +`; -function testAnnotation(this: PluginTestContext): void { - const anno: arkts.AnnotationUsage = annotation('State'); - expect(arkts.isAnnotationUsage(anno)).toBeTruthy(); - expect(anno.dumpSrc()).toBe('@State() '); +function testCheckAnnotation(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedCheckSnapshot)); } pluginTester.run( 'annotation', - [], + [addAnnotation, removeAnnotation, recheck], { - parsed: [testAnnotation], - checked: [testAnnotation], + 'parsed:add-annotation': [testParseAnnotation], + 'checked:add-annotation': [testCheckAnnotation], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts index a3d7d2909..0580721bd 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/argument-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -28,7 +29,8 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUN const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @functions.OptionalParametersAnnotation({minArgCount:3}) 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)): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 5); @@ -99,7 +101,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform argument calls in functions', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts index db15946ae..c589a4416 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/declare-and-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -80,7 +82,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform declare functions and calls', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts index 8e5494643..0fcc23735 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/inner-functions.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} function foo(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -102,7 +104,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform inner functions', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts index 53e3243e1..efc062d40 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/non-void-return-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} function funcNum(__memo_context: __memo_context_type, __memo_id: __memo_id_type): number { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -102,7 +104,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform functions with non-void return type', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts index 7db7cd676..3a9f19848 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/type-reference.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() function A(__memo_context: __memo_context_type, __memo_id: __memo_id_type): Attribute function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): ItemBuilder { @@ -82,7 +84,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform functions with type reference', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts b/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts index 08c0eb3bd..639b0c61f 100644 --- a/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/function-declarations/void-return-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const FUNCTION_DIR_PATH: string = 'memo/functions'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo function', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} function func(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -51,7 +53,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform functions with void return type', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts b/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts index f23a8d252..a9d1f2546 100644 --- a/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/lambda-literals/argument-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const LAMBDA_DIR_PATH: string = 'memo/lambdas'; @@ -28,7 +29,8 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, LAM const pluginTester = new PluginTester('test memo lambda', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} ((arg: (()=> void)) => {})((() => {})); @@ -163,7 +165,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform argument calls in lambdas', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts b/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts index f023fef13..f623bb63d 100644 --- a/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/lambda-literals/trailing-lambdas.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const LAMBDA_DIR_PATH: string = 'memo/lambdas'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo lambda', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -159,7 +161,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform trailing lambdas', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts b/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts index 59b48a024..56c92b9de 100644 --- a/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/lambda-literals/void-lambda.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const LAMBDA_DIR_PATH: string = 'memo/lambdas'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo lambda', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -63,7 +65,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform lambdas with void return type', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts b/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts index 4f6e3fa92..2076e3bc1 100644 --- a/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/lambda-literals/with-receiver.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const LAMBDA_DIR_PATH: string = 'memo/lambdas'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo lambda', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -115,7 +117,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform lambdas with receiver', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts index de72519e7..0d8dfbc7f 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/argument-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -28,7 +29,8 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, MET const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} class Test { 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)): void { @@ -135,7 +137,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform argument calls in methods', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts index 7657e1dd0..7a85fdba7 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/callable.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -28,7 +29,8 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, MET const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -102,7 +104,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform callable class', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts index 0a669b4c0..ed156ae94 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/declare-and-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -73,7 +75,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform declare methods and calls', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts index 095b43a43..57908bc9c 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/internal-calls.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -28,6 +29,7 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, MET const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; function main() {} function __context(): __memo_context_type @@ -176,7 +178,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform inner calls in methods', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts index f8bba95f0..671ddee8d 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/non-void-method.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -28,6 +29,7 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, MET const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; function main() {} function __context(): __memo_context_type @@ -62,14 +64,14 @@ class Test { } return __memo_scope.recache(__memo_parameter_arg.value); } - public intrinsic_method(): int { + @memo_intrinsic() public intrinsic_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): int { return 0; } - public intrinsic_method_with_this(): 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; } - 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 __context(); }); @@ -109,7 +111,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform methods with non-void return type', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts b/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts index 953742b8a..67059cc64 100644 --- a/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/method-declarations/void-method.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const METHOD_DIR_PATH: string = 'memo/methods'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo method', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} class A { public x: int; @@ -141,7 +143,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform methods with void return type', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts b/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts index c912aba8d..7f0b63298 100644 --- a/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/property-declarations/class-constructor.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const PROPERTY_DIR_PATH: string = 'memo/properties'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo property', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -91,7 +93,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform properties in class constructor', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts b/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts index 3be259236..688ba5e7f 100644 --- a/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/property-declarations/class-properties.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const PROPERTY_DIR_PATH: string = 'memo/properties'; @@ -30,7 +31,8 @@ buildConfig.compileFiles = [ const pluginTester = new PluginTester('test memo property', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} class A { public arg: (()=> void); @@ -96,7 +98,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform properties in class', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts b/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts index 99053d0ef..61e3c4254 100644 --- a/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts +++ b/arkui-plugins/test/ut/memo-plugins/property-declarations/interfaces.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const PROPERTY_DIR_PATH: string = 'memo/properties'; @@ -28,7 +29,8 @@ buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, PRO const pluginTester = new PluginTester('test memo property', buildConfig); const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; function main() {} @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { const __memo_scope = __memo_context.scope(((__memo_id) + ()), 0); @@ -97,7 +99,7 @@ function testMemoTransformer(this: PluginTestContext): void { pluginTester.run( 'transform interface properties', - [memoNoRecheck], + [memoNoRecheck, recheck], { 'checked:memo-no-recheck': [testMemoTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts index cae171a65..df521d7e6 100644 --- a/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/animation/animation-basic.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -37,22 +38,11 @@ const animationTransform: Plugins = { const pluginTester = new PluginTester('test basic animation transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; - import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; - import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Text as Text, Column as Column, Component as Component, Color as Color, Curve as Curve } from "@ohos.arkui.component"; - import { Entry as Entry } from "@ohos.arkui.component"; function main() {} @@ -81,15 +71,15 @@ function main() {} curve: Curve.Ease, }).width("100%"); return; - }), "AnimatableProperty", undefined, undefined); + }), "AnimatableProperty"); })); } - public constructor() {} + private constructor() {} } -interface __Options_AnimatablePropertyExample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_AnimatablePropertyExample { } @@ -97,7 +87,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { AnimatablePropertyExample._instantiateImpl(undefined, (() => { return new AnimatablePropertyExample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -111,7 +101,7 @@ function testAnimationTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic animation transform', - [animationTransform, uiNoRecheck], + [animationTransform, uiNoRecheck, recheck], { checked: [testAnimationTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts index b9a0d5943..6d4a42235 100644 --- a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -27,22 +28,23 @@ const CUSTOM_COMPONENT_DIR_PATH: string = 'custom-component'; const buildConfig: BuildConfig = mockBuildConfig(); buildConfig.compileFiles = [ - path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, CUSTOM_COMPONENT_DIR_PATH, 'custom-component-call.ets'), + path.resolve( + getRootPath(), + MOCK_ENTRY_DIR_PATH, + BUILDER_LAMBDA_DIR_PATH, + CUSTOM_COMPONENT_DIR_PATH, + 'custom-component-call.ets' + ), ]; const pluginTester = new PluginTester('test custom component call transformation', buildConfig); const parsedTransform: Plugins = { name: 'custom-component-call', - parsed: uiTransform().parsed + parsed: uiTransform().parsed, }; const expectedParsedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; -import { memo as memo } from "@ohos.arkui.stateManagement"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Text as Text, Column as Column, Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; @@ -72,7 +74,7 @@ import { Text as Text, Column as Column, Component as Component, Builder as Buil } interface __Options_CustomContainer { - closer?: @memo() (()=> void); + @BuilderParam() closer?: (()=> void); } interface __Options_CustomContainerUser { @@ -155,7 +157,7 @@ function testCustomComponentTransformer(this: PluginTestContext): void { pluginTester.run( 'test custom component call transformation', - [parsedTransform, recheck, uiNoRecheck], + [parsedTransform, recheck, uiNoRecheck, recheck], { parsed: [testParedTransformer], 'checked:builder-lambda-no-recheck': [testCustomComponentTransformer], diff --git a/arkui-plugins/test/ut/ui-plugins/builder-lambda/simple-component.test.ts b/arkui-plugins/test/ut/ui-plugins/builder-lambda/simple-component.test.ts index 37b4605ad..261d56508 100644 --- a/arkui-plugins/test/ut/ui-plugins/builder-lambda/simple-component.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/builder-lambda/simple-component.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 { builderLambdaNoRecheck, memoNoRecheck, recheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; const BUILDER_LAMBDA_DIR_PATH: string = 'builder-lambda'; @@ -31,7 +32,7 @@ const pluginTester = new PluginTester('test builder-lambda simple component', bu function testBuilderLambdaTransformer(this: PluginTestContext): void { const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; import { Column as Column, UIColumnAttribute as UIColumnAttribute } from \"arkui.component.column\"; function main() {} class MyStateSample { @@ -46,7 +47,8 @@ class MyStateSample { function testMemoTransformer(this: PluginTestContext): void { const expectedScript: string = ` -import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; +import { memo as memo } from \"@ohos.arkui.stateManagement\"; import { Column as Column, UIColumnAttribute as UIColumnAttribute } from \"arkui.component.column\"; function main() {} class MyStateSample { @@ -80,7 +82,7 @@ class MyStateSample { pluginTester.run( 'transform simple component', - [builderLambdaNoRecheck, recheck, memoNoRecheck], + [builderLambdaNoRecheck, recheck, memoNoRecheck, recheck], { 'checked:builder-lambda-no-recheck': [testBuilderLambdaTransformer], 'checked:memo-no-recheck': [testMemoTransformer], diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts index ba63b9e2d..84bef3fa3 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -33,15 +34,11 @@ const pluginTester = new PluginTester('test builder param variable passing', bui const parsedTransform: Plugins = { name: 'builder-param-passing', - parsed: uiTransform().parsed + parsed: uiTransform().parsed, }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Entry as Entry, Builder as Builder, BuilderParam as BuilderParam, Column as Column, Text as Text } from "@ohos.arkui.component"; @@ -71,7 +68,7 @@ function main() {} (this).customBuilderParam(); } - public constructor() {} + private constructor() {} } @@ -105,15 +102,15 @@ function main() {} }), undefined); })); } - public constructor() {} + private constructor() {} } -interface __Options_Child { - set customBuilderParam(customBuilderParam: @memo() (()=> void) | undefined) +@Component({freezeWhenInactive:false}) interface __Options_Child { + set customBuilderParam(@memo() customBuilderParam: (()=> void) | undefined) get customBuilderParam(): @memo() (()=> void) | undefined } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { } `; @@ -123,7 +120,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test builder param variable passing', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts index 336ee7389..17cd825c5 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/init-with-local-builder.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Builder as Builder, BuilderParam as BuilderParam } from "@ohos.arkui.component"; @@ -73,13 +72,13 @@ function main() {} (this).customBuilderParam(); (this).customBuilderParam2("hello"); } - public constructor() {} + private constructor() {} } -interface __Options_Child { - set customBuilderParam(customBuilderParam: @memo() (()=> void) | undefined) +@Component({freezeWhenInactive:false}) interface __Options_Child { + set customBuilderParam(@memo() customBuilderParam: (()=> void) | undefined) get customBuilderParam(): @memo() (()=> void) | undefined - set customBuilderParam2(customBuilderParam2: @memo() ((str: string)=> void) | undefined) + set customBuilderParam2(@memo() customBuilderParam2: ((str: string)=> void) | undefined) get customBuilderParam2(): @memo() ((str: string)=> void) | undefined } `; @@ -90,7 +89,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test builder param init with local builder', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts index 09ffcfbaa..0a36485c9 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder/global-builder.test.ts @@ -14,46 +14,41 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; const FUNCTION_DIR_PATH: string = 'decorators/builder'; const buildConfig: BuildConfig = mockBuildConfig(); -buildConfig.compileFiles = [ - path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'global-builder.ets'), -]; +buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'global-builder.ets')]; const pluginTester = new PluginTester('test global builder', buildConfig); const parsedTransform: Plugins = { name: 'global-builder', - parsed: uiTransform().parsed + parsed: uiTransform().parsed, }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIRowAttribute as UIRowAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Row as Row, Builder as Builder, Text as Text } from "@ohos.arkui.component"; function main() {} @memo() function showTextBuilder() { - Text(undefined, "Hello World", undefined, undefined); + Text(undefined, "Hello World"); } @memo() function overBuilder(params: Tmp) { Row(undefined, undefined, (() => { - Text(undefined, (("UseStateVarByReference: ") + (params.paramA1)), undefined, undefined); + Text(undefined, (("UseStateVarByReference: ") + (params.paramA1))); })); } @@ -73,10 +68,10 @@ class Tmp { }); })); } - public constructor() {} + private constructor() {} } -interface __Options_BuilderDemo { +@Component({freezeWhenInactive:false}) interface __Options_BuilderDemo { } `; @@ -87,7 +82,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'global builder', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts index 084238f23..e737ffe84 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder/local-builder.test.ts @@ -14,34 +14,30 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; const FUNCTION_DIR_PATH: string = 'decorators/builder'; const buildConfig: BuildConfig = mockBuildConfig(); -buildConfig.compileFiles = [ - path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'local-builder.ets'), -]; +buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, FUNCTION_DIR_PATH, 'local-builder.ets')]; const pluginTester = new PluginTester('test local builder', buildConfig); const parsedTransform: Plugins = { name: 'local-builder', - parsed: uiTransform().parsed + parsed: uiTransform().parsed, }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Column as Column, Builder as Builder, Text as Text } from "@ohos.arkui.component"; @@ -54,13 +50,13 @@ function main() {} Text(@memo() ((instance: UITextAttribute): void => { instance.fontSize(30); return; - }), "Hello World", undefined, undefined); + }), "Hello World"); } @memo() public showTextValueBuilder(param: string) { Text(@memo() ((instance: UITextAttribute): void => { instance.fontSize(30); return; - }), param, undefined, undefined); + }), param); } @memo() public _build(@memo() style: ((instance: BuilderDemo)=> BuilderDemo) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_BuilderDemo | undefined): void { Column(undefined, undefined, @memo() (() => { @@ -68,10 +64,10 @@ function main() {} (this).showTextValueBuilder("Hello @Builder"); })); } - public constructor() {} + private constructor() {} } -interface __Options_BuilderDemo { +@Component({freezeWhenInactive:false}) interface __Options_BuilderDemo { } `; @@ -82,7 +78,7 @@ function testCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'local builder', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { 'checked:ui-no-recheck': [testCheckedTransformer], }, diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts index 5a798dab0..29c368ffb 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-basic-type.test.ts @@ -143,7 +143,7 @@ pluginTester.run( 'test basic type @Link decorated variables transformation', [parsedTransform, structNoRecheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts index 927e91220..fdfbfb35d 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-complex-type.test.ts @@ -306,7 +306,7 @@ pluginTester.run( 'test complex type @Link decorated variables transformation', [parsedTransform, structNoRecheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts index 6e903b659..bf38c4bd0 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/link-to-link-prop-state.test.ts @@ -178,7 +178,7 @@ pluginTester.run( 'test @Link decorated variables passing to other variables', [parsedTransform, uiNoRecheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts index 300ebc5a9..b8d8017e2 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/link/state-to-link.test.ts @@ -153,7 +153,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { ParentComponent._instantiateImpl(undefined, (() => { return new ParentComponent(); - }), undefined, undefined, undefined); + })); } public constructor() {} } @@ -167,7 +167,7 @@ pluginTester.run( 'test @Link decorated variables passing', [parsedTransform, uiNoRecheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts index 55af0dd86..9cbfac33e 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-only.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,14 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed only transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Observed as Observed } from "@ohos.arkui.stateManagement"; function main() {} @@ -131,11 +116,11 @@ function main() {} @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -147,9 +132,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed only transform', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts index becd4ced5..f02f78f51 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-class-property.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,16 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed track transform with class property', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Observed as Observed, Track as Track } from "@ohos.arkui.stateManagement"; function main() {} @@ -181,11 +168,11 @@ class E implements IObservedObject { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } `; @@ -196,9 +183,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with class property', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts index b0635b8a9..6d875a0ba 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,32 +38,17 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed track transform with complex type', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; - import { Observed as Observed, Track as Track } from "@ohos.arkui.stateManagement"; function main() {} @@ -862,11 +848,11 @@ class mixed3 implements IObservedObject { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -874,7 +860,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -888,9 +874,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with complex type', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts index 47237cf0c..bdd7edd92 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-extends.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,14 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed track transform with extends', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Observed as Observed, Track as Track } from "@ohos.arkui.stateManagement"; function main() {} @@ -178,11 +163,11 @@ class G extends A { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -194,9 +179,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with extends', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts index c4239714b..cc077de25 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track-implements.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,14 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed track transform with implements', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Observed as Observed } from "@ohos.arkui.stateManagement"; function main() {} @@ -161,11 +146,11 @@ interface trackInterface { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -177,9 +162,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed track transform with implements', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts index 95a77ed88..8767bdc86 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/observed-track.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,14 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test observed with track transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Observed as Observed, Track as Track } from "@ohos.arkui.stateManagement"; function main() {} @@ -116,11 +101,11 @@ function main() {} @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -132,9 +117,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test observed with track transform', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts index c21fe95f3..20dbe50b4 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/observed-track/track-only.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,30 +38,14 @@ const observedTrackTransform: Plugins = { const pluginTester = new PluginTester('test track only transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component } from "@ohos.arkui.component"; - import { Track as Track } from "@ohos.arkui.stateManagement"; function main() {} @@ -116,11 +101,11 @@ class C implements IObservedObject { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @@ -132,9 +117,9 @@ function testObservedOnlyTransformer(this: PluginTestContext): void { pluginTester.run( 'test track only transform', - [observedTrackTransform, uiNoRecheck], + [observedTrackTransform, uiNoRecheck, recheck], { - checked: [testObservedOnlyTransformer], + 'checked:ui-no-recheck': [testObservedOnlyTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts index b25b5c22d..215c88b78 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-basic-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { PropDecoratedVariable as PropDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -118,10 +117,10 @@ function main() {} (this).__backing_propVar5!.set(value); } @memo() public _build(@memo() style: ((instance: PropParent)=> PropParent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_PropParent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_PropParent { +@Component({freezeWhenInactive:false}) interface __Options_PropParent { set propVar1(propVar1: string | undefined) get propVar1(): string | undefined set __backing_propVar1(__backing_propVar1: PropDecoratedVariable | undefined) @@ -136,8 +135,8 @@ interface __Options_PropParent { get __backing_propVar3(): PropDecoratedVariable | undefined set propVar4(propVar4: undefined | undefined) get propVar4(): undefined | undefined - set __backing_propVar4(__backing_propVar4: PropDecoratedVariable | undefined) - get __backing_propVar4(): PropDecoratedVariable | undefined + set __backing_propVar4(__backing_propVar4: undefined | undefined) + get __backing_propVar4(): undefined | undefined set propVar5(propVar5: null | undefined) get propVar5(): null | undefined set __backing_propVar5(__backing_propVar5: PropDecoratedVariable | undefined) @@ -151,9 +150,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Prop decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts index 312db0a77..d6c049f75 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/prop-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { PropDecoratedVariable as PropDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -266,10 +265,10 @@ final class PropType extends BaseEnum { (this).__backing_propVar12!.set(value); } @memo() public _build(@memo() style: ((instance: Parent)=> Parent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Parent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { set propVar1(propVar1: Per | undefined) get propVar1(): Per | undefined set __backing_propVar1(__backing_propVar1: PropDecoratedVariable | undefined) @@ -312,12 +311,12 @@ interface __Options_Parent { get __backing_propVar10(): PropDecoratedVariable> | undefined set propVar11(propVar11: string | number | undefined) get propVar11(): string | number | undefined - set __backing_propVar11(__backing_propVar11: PropDecoratedVariable | undefined) - get __backing_propVar11(): PropDecoratedVariable | undefined + set __backing_propVar11(__backing_propVar11: PropDecoratedVariable | PropDecoratedVariable | undefined) + get __backing_propVar11(): PropDecoratedVariable | PropDecoratedVariable | undefined set propVar12(propVar12: Set | Per | undefined) get propVar12(): Set | Per | undefined - set __backing_propVar12(__backing_propVar12: PropDecoratedVariable | Per> | undefined) - get __backing_propVar12(): PropDecoratedVariable | Per> | undefined + set __backing_propVar12(__backing_propVar12: PropDecoratedVariable> | PropDecoratedVariable | undefined) + get __backing_propVar12(): PropDecoratedVariable> | PropDecoratedVariable | undefined } `; @@ -327,9 +326,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Prop decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts index 787797bc6..da5fbaff6 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/prop/state-to-prop.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,14 +38,10 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; -import { memo as memo } from "@ohos.arkui.stateManagement"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; import { PropDecoratedVariable as PropDecoratedVariable } from "@ohos.arkui.stateManagement"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; +import { memo as memo } from "@ohos.arkui.stateManagement"; import { UIButtonAttribute as UIButtonAttribute } from "@ohos.arkui.component"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Text as Text, Button as Button, Column as Column, ClickEvent as ClickEvent } from "@ohos.arkui.component"; import { Prop as Prop, State as State } from "@ohos.arkui.stateManagement"; @@ -82,19 +79,19 @@ function main() {} @memo() public _build(@memo() style: ((instance: CountDownComponent)=> CountDownComponent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_CountDownComponent | undefined): void { Column(undefined, undefined, (() => { if ((((this).count) > (0))) { - Text(undefined, (((("You have") + ((this).count))) + ("Nuggets left")), undefined, undefined); + Text(undefined, (((("You have") + ((this).count))) + ("Nuggets left"))); } else { - Text(undefined, "Game over!", undefined, undefined); + Text(undefined, "Game over!"); } Button(@memo() ((instance: UIButtonAttribute): void => { instance.onClick(((e: ClickEvent) => { (this).count -= (this).costOfOneAttempt; })); return; - }), "Try again", undefined, undefined); + }), "Try again"); })); } - public constructor() {} + private constructor() {} } @Component({freezeWhenInactive:false}) final class ParentComponent extends CustomComponent { @@ -112,31 +109,31 @@ function main() {} } @memo() public _build(@memo() style: ((instance: ParentComponent)=> ParentComponent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_ParentComponent | undefined): void { Column(undefined, undefined, (() => { - Text(undefined, (((("Grant") + ((this).countDownStartValue))) + ("nuggets to play.")), undefined, undefined); + Text(undefined, (((("Grant") + ((this).countDownStartValue))) + ("nuggets to play."))); Button(@memo() ((instance: UIButtonAttribute): void => { instance.onClick(((e: ClickEvent) => { (this).countDownStartValue += 1; })); return; - }), "+1 - Nuggets in New Game", undefined, undefined); + }), "+1 - Nuggets in New Game"); Button(@memo() ((instance: UIButtonAttribute): void => { instance.onClick(((e: ClickEvent) => { (this).countDownStartValue -= 1; })); return; - }), "-1 - Nuggets in New Game", undefined, undefined); + }), "-1 - Nuggets in New Game"); CountDownComponent._instantiateImpl(undefined, (() => { return new CountDownComponent(); }), ({ count: (this).countDownStartValue, costOfOneAttempt: 2, - } as __Options_CountDownComponent), undefined, undefined); + } as __Options_CountDownComponent)); })); } - public constructor() {} + private constructor() {} } -interface __Options_CountDownComponent { +@Component({freezeWhenInactive:false}) interface __Options_CountDownComponent { set count(count: number | undefined) get count(): number | undefined set __backing_count(__backing_count: PropDecoratedVariable | undefined) @@ -145,7 +142,7 @@ interface __Options_CountDownComponent { get costOfOneAttempt(): number | undefined } -interface __Options_ParentComponent { +@Component({freezeWhenInactive:false}) interface __Options_ParentComponent { set countDownStartValue(countDownStartValue: number | undefined) get countDownStartValue(): number | undefined set __backing_countDownStartValue(__backing_countDownStartValue: StateDecoratedVariable | undefined) @@ -159,9 +156,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @Prop decorated variables passing', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts index 5239317ac..4fc710722 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-annotation-usage.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { ProvideDecoratedVariable as ProvideDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -124,42 +123,42 @@ function main() {} (this).__backing_count7!.set(value); } @memo() public _build(@memo() style: ((instance: Ancestors)=> Ancestors) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Ancestors | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_Ancestors { +@Component({freezeWhenInactive:false}) interface __Options_Ancestors { set count(count: string | undefined | undefined) get count(): string | undefined | undefined - set __backing_count(__backing_count: ProvideDecoratedVariable | undefined) - get __backing_count(): ProvideDecoratedVariable | undefined + set __backing_count(__backing_count: ProvideDecoratedVariable | undefined | undefined) + get __backing_count(): ProvideDecoratedVariable | undefined | undefined set count1(count1: string | undefined | undefined) get count1(): string | undefined | undefined - set __backing_count1(__backing_count1: ProvideDecoratedVariable | undefined) - get __backing_count1(): ProvideDecoratedVariable | undefined + set __backing_count1(__backing_count1: ProvideDecoratedVariable | undefined | undefined) + get __backing_count1(): ProvideDecoratedVariable | undefined | undefined set count2(count2: string | undefined | undefined) get count2(): string | undefined | undefined - set __backing_count2(__backing_count2: ProvideDecoratedVariable | undefined) - get __backing_count2(): ProvideDecoratedVariable | undefined + set __backing_count2(__backing_count2: ProvideDecoratedVariable | undefined | undefined) + get __backing_count2(): ProvideDecoratedVariable | undefined | undefined set count3(count3: string | undefined | undefined) get count3(): string | undefined | undefined - set __backing_count3(__backing_count3: ProvideDecoratedVariable | undefined) - get __backing_count3(): ProvideDecoratedVariable | undefined + set __backing_count3(__backing_count3: ProvideDecoratedVariable | undefined | undefined) + get __backing_count3(): ProvideDecoratedVariable | undefined | undefined set count4(count4: string | undefined | undefined) get count4(): string | undefined | undefined - set __backing_count4(__backing_count4: ProvideDecoratedVariable | undefined) - get __backing_count4(): ProvideDecoratedVariable | undefined + set __backing_count4(__backing_count4: ProvideDecoratedVariable | undefined | undefined) + get __backing_count4(): ProvideDecoratedVariable | undefined | undefined set count5(count5: string | undefined | undefined) get count5(): string | undefined | undefined - set __backing_count5(__backing_count5: ProvideDecoratedVariable | undefined) - get __backing_count5(): ProvideDecoratedVariable | undefined + set __backing_count5(__backing_count5: ProvideDecoratedVariable | undefined | undefined) + get __backing_count5(): ProvideDecoratedVariable | undefined | undefined set count6(count6: string | undefined | undefined) get count6(): string | undefined | undefined - set __backing_count6(__backing_count6: ProvideDecoratedVariable | undefined) - get __backing_count6(): ProvideDecoratedVariable | undefined + set __backing_count6(__backing_count6: ProvideDecoratedVariable | undefined | undefined) + get __backing_count6(): ProvideDecoratedVariable | undefined | undefined set count7(count7: string | undefined | undefined) get count7(): string | undefined | undefined - set __backing_count7(__backing_count7: ProvideDecoratedVariable | undefined) - get __backing_count7(): ProvideDecoratedVariable | undefined + set __backing_count7(__backing_count7: ProvideDecoratedVariable | undefined | undefined) + get __backing_count7(): ProvideDecoratedVariable | undefined | undefined } `; @@ -169,9 +168,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test different @Provide annotation usage transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts index 8ce1a14e5..404176499 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-basic-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { ProvideDecoratedVariable as ProvideDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -97,10 +96,10 @@ function main() {} (this).__backing_provideVar5!.set(value); } @memo() public _build(@memo() style: ((instance: PropParent)=> PropParent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_PropParent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_PropParent { +@Component({freezeWhenInactive:false}) interface __Options_PropParent { set provideVar1(provideVar1: string | undefined) get provideVar1(): string | undefined set __backing_provideVar1(__backing_provideVar1: ProvideDecoratedVariable | undefined) @@ -115,8 +114,8 @@ interface __Options_PropParent { get __backing_provideVar3(): ProvideDecoratedVariable | undefined set provideVar4(provideVar4: undefined | undefined) get provideVar4(): undefined | undefined - set __backing_provideVar4(__backing_provideVar4: ProvideDecoratedVariable | undefined) - get __backing_provideVar4(): ProvideDecoratedVariable | undefined + set __backing_provideVar4(__backing_provideVar4: undefined | undefined) + get __backing_provideVar4(): undefined | undefined set provideVar5(provideVar5: null | undefined) get provideVar5(): null | undefined set __backing_provideVar5(__backing_provideVar5: ProvideDecoratedVariable | undefined) @@ -130,9 +129,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @Provide decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts index 0a2eb5ae7..3aa06a1cc 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/provide-and-consume/provide-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { ProvideDecoratedVariable as ProvideDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -217,10 +216,10 @@ final class PropType extends BaseEnum { (this).__backing_provideVar12!.set(value); } @memo() public _build(@memo() style: ((instance: Parent)=> Parent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Parent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { set provideVar1(provideVar1: Per | undefined) get provideVar1(): Per | undefined set __backing_provideVar1(__backing_provideVar1: ProvideDecoratedVariable | undefined) @@ -263,12 +262,12 @@ interface __Options_Parent { get __backing_provideVar10(): ProvideDecoratedVariable> | undefined set provideVar11(provideVar11: string | number | undefined) get provideVar11(): string | number | undefined - set __backing_provideVar11(__backing_provideVar11: ProvideDecoratedVariable | undefined) - get __backing_provideVar11(): ProvideDecoratedVariable | undefined + set __backing_provideVar11(__backing_provideVar11: ProvideDecoratedVariable | ProvideDecoratedVariable | undefined) + get __backing_provideVar11(): ProvideDecoratedVariable | ProvideDecoratedVariable | undefined set provideVar12(provideVar12: Set | Per | undefined) get provideVar12(): Set | Per | undefined - set __backing_provideVar12(__backing_provideVar12: ProvideDecoratedVariable | Per> | undefined) - get __backing_provideVar12(): ProvideDecoratedVariable | Per> | undefined + set __backing_provideVar12(__backing_provideVar12: ProvideDecoratedVariable> | ProvideDecoratedVariable | undefined) + get __backing_provideVar12(): ProvideDecoratedVariable> | ProvideDecoratedVariable | undefined } `; @@ -278,9 +277,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @Provide decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts index 1925eef83..a458fa042 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-build.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -33,21 +34,15 @@ const pluginTester = new PluginTester('test resource transform in build method', const parsedTransform: Plugins = { name: 'resource-in-build', - parsed: uiTransform().parsed + parsed: uiTransform().parsed, }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; -import { UIImageAnimatorAttribute as UIImageAnimatorAttribute } from "@ohos.arkui.component"; -import { UISelectAttribute as UISelectAttribute } from "@ohos.arkui.component"; -import { UITextInputAttribute as UITextInputAttribute } from "@ohos.arkui.component"; -import { UIImageAttribute as UIImageAttribute } from "@ohos.arkui.component"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; import { _rawfile as _rawfile } from "@ohos.arkui.component"; import { _r as _r } from "@ohos.arkui.component"; +import { UIImageAnimatorAttribute as UIImageAnimatorAttribute } from "@ohos.arkui.component"; +import { UIImageAttribute as UIImageAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, $r as $r, $rawfile as $rawfile, Column as Column, Text as Text, Image as Image, TextInput as TextInput, Select as Select, SelectOption as SelectOption, Margin as Margin, ImageAnimator as ImageAnimator } from "@ohos.arkui.component"; @@ -78,13 +73,13 @@ function main() {} @memo() public _build(@memo() style: ((instance: ResourceComponent)=> ResourceComponent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_ResourceComponent | undefined): void { Column(undefined, undefined, (() => { - Text(undefined, _r("", "", "app.string.app_name"), undefined, undefined); - Image(undefined, _rawfile("", "", "app.photo.png"), undefined, undefined); + Text(undefined, _r("", "", "app.string.app_name")); + Image(undefined, _rawfile("", "", "app.photo.png")); TextInput(undefined, { text: _r("", "", "app.string.input_content"), - }, undefined); - Text(undefined, _r("", "", (this).str1), undefined, undefined); - Text(undefined, _r("", "", (this).str2), undefined, undefined); + }); + Text(undefined, _r("", "", (this).str1)); + Text(undefined, _r("", "", (this).str2)); Select(undefined, new Array({ value: "aaa", icon: _r("", "", "app.media.selection"), @@ -97,14 +92,14 @@ function main() {} }, { value: "ddd", icon: _r("", "", "app.media.selection"), - }), undefined); + })); Image(@memo() ((instance: UIImageAttribute): void => { instance.margin(({ top: _r("", "", "app.float.elements_margin_horizontal_m"), bottom: _r("", "", "app.float.elements_margin_horizontal_l"), } as Margin)); return; - }), _r("", "", "app.media.app_icon"), undefined, undefined); + }), _r("", "", "app.media.app_icon")); ImageAnimator(@memo() ((instance: UIImageAnimatorAttribute): void => { instance.images([{ src: _r("", "", "app.media.aaa"), @@ -112,13 +107,13 @@ function main() {} src: _r("", "", "app.media.bbb"), }]); return; - }), undefined); + })); })); } - public constructor() {} + private constructor() {} } -interface __Options_ResourceComponent { +@Component({freezeWhenInactive:false}) interface __Options_ResourceComponent { set str1(str1: string | undefined) get str1(): string | undefined set str2(str2: string | undefined) @@ -132,9 +127,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test resource transform in build method', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts index 60451251c..b410d8b18 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/resource/resource-in-property.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,12 +38,7 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; -import { UIImageAttribute as UIImageAttribute } from "@ohos.arkui.component"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; import { _rawfile as _rawfile } from "@ohos.arkui.component"; import { _r as _r } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -76,15 +72,15 @@ i = _r("", "", "app.string.app_name"); } @memo() public _build(@memo() style: ((instance: ResourceComponent)=> ResourceComponent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_ResourceComponent | undefined): void { Column(undefined, undefined, (() => { - Text(undefined, (this).str, undefined, undefined); - Text(undefined, i, undefined, undefined); - Image(undefined, (this).icon, undefined, undefined); + Text(undefined, (this).str); + Text(undefined, i); + Image(undefined, (this).icon); })); } - public constructor() {} + private constructor() {} } -interface __Options_ResourceComponent { +@Component({freezeWhenInactive:false}) interface __Options_ResourceComponent { set str(str: Resource | undefined) get str(): Resource | undefined set icon(icon: Resource | undefined) @@ -98,9 +94,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test resource transform in property', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index f4a20b03e..c9148c6e8 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,22 +38,12 @@ const reusableTransform: Plugins = { const pluginTester = new PluginTester('test basic reusable', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - -import { memo as memo } from "@ohos.arkui.stateManagement"; - import { DecoratedV1VariableBase as DecoratedV1VariableBase } from "@ohos.arkui.stateManagement"; - -import { LinkDecoratedVariable as LinkDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; - +import { LinkDecoratedVariable as LinkDecoratedVariable } from "@ohos.arkui.stateManagement"; +import { memo as memo } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Reusable as Reusable } from "@ohos.arkui.component"; - import { State as State, Link as Link } from "@ohos.arkui.stateManagement"; function main() {} @@ -69,10 +60,10 @@ function main() {} return new Child(); }), ({ num: 5, - } as __Options_Child), undefined, "Child"); + } as __Options_Child), "Child"); } - public constructor() {} + private constructor() {} } @@ -118,18 +109,18 @@ function main() {} @memo() public _build(@memo() style: ((instance: Child)=> Child) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Child | undefined): void {} - public constructor() {} + private constructor() {} } - -interface __Options_MyStateSample { +@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } -interface __Options_Child { - set num(num: number | undefined) +@Component({freezeWhenInactive:false}) @Reusable() interface __Options_Child { + @__Link_intrinsic() set num(num: number | undefined) - get num(): number | undefined + @__Link_intrinsic() get num(): number | undefined set __backing_num(__backing_num: DecoratedV1VariableBase | undefined) get __backing_num(): DecoratedV1VariableBase | undefined @@ -149,9 +140,9 @@ function testReusableTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic reusable', - [reusableTransform, uiNoRecheck], + [reusableTransform, uiNoRecheck, recheck], { - checked: [testReusableTransformer], + 'checked:ui-no-recheck': [testReusableTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts index dbbd61448..89be56030 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-complex.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,26 +38,14 @@ const reusableTransform: Plugins = { const pluginTester = new PluginTester('test complex reusable', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - -import { memo as memo } from "@ohos.arkui.stateManagement"; - +import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; - +import { memo as memo } from "@ohos.arkui.stateManagement"; import { UIButtonAttribute as UIButtonAttribute } from "@ohos.arkui.component"; - -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; - import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; - import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Entry as Entry, Reusable as Reusable, Column as Column, Text as Text, Button as Button, ClickEvent as ClickEvent, FontWeight as FontWeight } from "@ohos.arkui.component"; - import { State as State } from "@ohos.arkui.stateManagement"; function main() {} @@ -100,18 +89,18 @@ class Message { (this).display = !((this).display); })); return; - }), "Hello", undefined, undefined); + }), "Hello"); if ((this).display) { Child._instantiateImpl(undefined, (() => { return new Child(); }), ({ message: new Message("Child"), - } as __Options_Child), undefined, "Child"); + } as __Options_Child), "Child"); } })); } - public constructor() {} + private constructor() {} } @@ -152,15 +141,15 @@ class Message { Text(@memo() ((instance: UITextAttribute): void => { instance.fontSize(30); return; - }), (this).message.value, undefined, undefined); + }), (this).message.value); })); } - public constructor() {} + private constructor() {} } -interface __Options_Index { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_Index { set display(display: boolean | undefined) get display(): boolean | undefined @@ -170,7 +159,7 @@ interface __Options_Index { } -interface __Options_Child { +@Reusable() @Component({freezeWhenInactive:false}) interface __Options_Child { set message(message: Message | undefined) get message(): Message | undefined @@ -184,7 +173,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -199,9 +188,9 @@ function testReusableTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex reusable', - [reusableTransform, uiNoRecheck], + [reusableTransform, uiNoRecheck, recheck], { - checked: [testReusableTransformer], + 'checked:ui-no-recheck': [testReusableTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts index a3258fa0b..4203078ac 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-basic-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -97,10 +96,10 @@ function main() {} (this).__backing_stateVar5!.set(value); } @memo() public _build(@memo() style: ((instance: Parent)=> Parent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Parent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { set stateVar1(stateVar1: string | undefined) get stateVar1(): string | undefined set __backing_stateVar1(__backing_stateVar1: StateDecoratedVariable | undefined) @@ -115,8 +114,8 @@ interface __Options_Parent { get __backing_stateVar3(): StateDecoratedVariable | undefined set stateVar4(stateVar4: undefined | undefined) get stateVar4(): undefined | undefined - set __backing_stateVar4(__backing_stateVar4: StateDecoratedVariable | undefined) - get __backing_stateVar4(): StateDecoratedVariable | undefined + set __backing_stateVar4(__backing_stateVar4: undefined | undefined) + get __backing_stateVar4(): undefined | undefined set stateVar5(stateVar5: null | undefined) get stateVar5(): null | undefined set __backing_stateVar5(__backing_stateVar5: StateDecoratedVariable | undefined) @@ -130,9 +129,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic type @State decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts index eeec6cdc4..eae23bbe5 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { structNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,8 +38,6 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; @@ -217,10 +216,10 @@ final class StateType extends BaseEnum { (this).__backing_stateVar12!.set(value); } @memo() public _build(@memo() style: ((instance: Parent)=> Parent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Parent | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { set stateVar1(stateVar1: Per | undefined) get stateVar1(): Per | undefined set __backing_stateVar1(__backing_stateVar1: StateDecoratedVariable | undefined) @@ -263,12 +262,12 @@ interface __Options_Parent { get __backing_stateVar10(): StateDecoratedVariable> | undefined set stateVar11(stateVar11: string | number | undefined) get stateVar11(): string | number | undefined - set __backing_stateVar11(__backing_stateVar11: StateDecoratedVariable | undefined) - get __backing_stateVar11(): StateDecoratedVariable | undefined + set __backing_stateVar11(__backing_stateVar11: StateDecoratedVariable | StateDecoratedVariable | undefined) + get __backing_stateVar11(): StateDecoratedVariable | StateDecoratedVariable | undefined set stateVar12(stateVar12: Set | Per | undefined) get stateVar12(): Set | Per | undefined - set __backing_stateVar12(__backing_stateVar12: StateDecoratedVariable | Per> | undefined) - get __backing_stateVar12(): StateDecoratedVariable | Per> | undefined + set __backing_stateVar12(__backing_stateVar12: StateDecoratedVariable> | StateDecoratedVariable | undefined) + get __backing_stateVar12(): StateDecoratedVariable> | StateDecoratedVariable | undefined } `; @@ -278,9 +277,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test complex type @State decorated variables transformation', - [parsedTransform, structNoRecheck], + [parsedTransform, structNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:struct-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts index eb7d0a500..c54a15e91 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/state/state-to-state.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,12 +38,8 @@ const parsedTransform: Plugins = { }; const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; -import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Column as Column, Text as Text } from "@ohos.arkui.component"; import { State as State } from "@ohos.arkui.stateManagement"; @@ -75,10 +72,10 @@ class Per { return new Child(); }), ({ childVar1: (this).parentVar1, - } as __Options_Child), undefined, undefined); + } as __Options_Child)); })); } - public constructor() {} + private constructor() {} } @Component({freezeWhenInactive:false}) final class Child extends CustomComponent { @@ -95,20 +92,20 @@ class Per { (this).__backing_childVar1!.set(value); } @memo() public _build(@memo() style: ((instance: Child)=> Child) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Child | undefined): void { - Text(undefined, (this).childVar1.str, undefined, undefined); + Text(undefined, (this).childVar1.str); } - public constructor() {} + private constructor() {} } -interface __Options_Parent { +@Component({freezeWhenInactive:false}) interface __Options_Parent { set parentVar1(parentVar1: Per | undefined) get parentVar1(): Per | undefined set __backing_parentVar1(__backing_parentVar1: StateDecoratedVariable | undefined) get __backing_parentVar1(): StateDecoratedVariable | undefined } -interface __Options_Child { +@Component({freezeWhenInactive:false}) interface __Options_Child { set childVar1(childVar1: Per | undefined) get childVar1(): Per | undefined set __backing_childVar1(__backing_childVar1: StateDecoratedVariable | undefined) @@ -122,9 +119,9 @@ function testParsedAndCheckedTransformer(this: PluginTestContext): void { pluginTester.run( 'test @State decorated variables passing', - [parsedTransform, uiNoRecheck], + [parsedTransform, uiNoRecheck, recheck], { - checked: [testParsedAndCheckedTransformer], + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts index 8e1832428..0f47a5e8a 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-appstorage.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,24 +38,12 @@ const storageLinkTransform: Plugins = { const pluginTester = new PluginTester('test storagelink with appstorage', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - -import { memo as memo } from "@ohos.arkui.stateManagement"; - import { StorageLinkDecoratedVariable as StorageLinkDecoratedVariable } from "@ohos.arkui.stateManagement"; - +import { memo as memo } from "@ohos.arkui.stateManagement"; import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; - -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; - import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Entry as Entry, Column as Column, Text as Text, ClickEvent as ClickEvent } from "@ohos.arkui.component"; - import { StorageLink as StorageLink, AppStorage as AppStorage } from "@ohos.arkui.stateManagement"; function main() {} @@ -106,21 +95,21 @@ class Data { (this).storageLink += 1; })); return; - }), \`From AppStorage \${(this).storageLink}\`, undefined, undefined); + }), \`From AppStorage \${(this).storageLink}\`); Text(@memo() ((instance: UITextAttribute): void => { instance.onClick(((e: ClickEvent) => { (this).storageLinkObject.code += 1; })); return; - }), \`From AppStorage \${(this).storageLinkObject.code}\`, undefined, undefined); + }), \`From AppStorage \${(this).storageLinkObject.code}\`); })); } - public constructor() {} + private constructor() {} } -interface __Options_Index { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_Index { set storageLink(storageLink: number | undefined) get storageLink(): number | undefined @@ -140,7 +129,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -154,9 +143,9 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink with appstorage', - [storageLinkTransform, uiNoRecheck], + [storageLinkTransform, uiNoRecheck, recheck], { - checked: [testStorageLinkTransformer], + 'checked:ui-no-recheck': [testStorageLinkTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts index c060b7a83..7a17f6200 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,10 +38,6 @@ const storageLinkTransform: Plugins = { const pluginTester = new PluginTester('test storagelink complex type transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; import { StorageLinkDecoratedVariable as StorageLinkDecoratedVariable } from "@ohos.arkui.stateManagement"; @@ -228,11 +225,11 @@ final class Status extends BaseEnum { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { set arrayA(arrayA: Array | undefined) get arrayA(): Array | undefined @@ -266,9 +263,9 @@ interface __Options_MyStateSample { set unionA(unionA: string | undefined | undefined) get unionA(): string | undefined | undefined - set __backing_unionA(__backing_unionA: StorageLinkDecoratedVariable | undefined) + set __backing_unionA(__backing_unionA: StorageLinkDecoratedVariable | undefined | undefined) - get __backing_unionA(): StorageLinkDecoratedVariable | undefined + get __backing_unionA(): StorageLinkDecoratedVariable | undefined | undefined set classA(classA: Person | undefined) get classA(): Person | undefined @@ -288,7 +285,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -303,9 +300,9 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink complex type transform', - [storageLinkTransform, uiNoRecheck], + [storageLinkTransform, uiNoRecheck, recheck], { - checked: [testStorageLinkTransformer], + 'checked:ui-no-recheck': [testStorageLinkTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts index e129e2600..3d69b5f83 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storagelink/storagelink-primitive-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,10 +38,6 @@ const storageLinkTransform: Plugins = { const pluginTester = new PluginTester('test storagelink primitive type transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; import { StorageLinkDecoratedVariable as StorageLinkDecoratedVariable } from "@ohos.arkui.stateManagement"; @@ -98,11 +95,11 @@ function main() {} @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { set numA(numA: number | undefined) get numA(): number | undefined @@ -128,7 +125,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -143,9 +140,9 @@ function testStorageLinkTransformer(this: PluginTestContext): void { pluginTester.run( 'test storagelink primitive type transform', - [storageLinkTransform, uiNoRecheck], + [storageLinkTransform, uiNoRecheck, recheck], { - checked: [testStorageLinkTransformer], + 'checked:ui-no-recheck': [testStorageLinkTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts index a403e00a9..49ca6a663 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-appstorage.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,24 +38,12 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test storageprop with appstorage', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - -import { memo as memo } from "@ohos.arkui.stateManagement"; - import { StoragePropDecoratedVariable as StoragePropDecoratedVariable } from "@ohos.arkui.stateManagement"; - +import { memo as memo } from "@ohos.arkui.stateManagement"; import { UITextAttribute as UITextAttribute } from "@ohos.arkui.component"; - -import { UIColumnAttribute as UIColumnAttribute } from "@ohos.arkui.component"; - import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Entry as Entry, Column as Column, Text as Text, ClickEvent as ClickEvent } from "@ohos.arkui.component"; - import { StorageProp as StorageProp, AppStorage as AppStorage } from "@ohos.arkui.stateManagement"; function main() {} @@ -106,21 +95,21 @@ class Data { (this).storageProp += 1; })); return; - }), \`From AppStorage \${(this).storageProp}\`, undefined, undefined); + }), \`From AppStorage \${(this).storageProp}\`); Text(@memo() ((instance: UITextAttribute): void => { instance.onClick(((e: ClickEvent) => { (this).storagePropObject.code += 1; })); return; - }), \`From AppStorage \${(this).storagePropObject.code}\`, undefined, undefined); + }), \`From AppStorage \${(this).storagePropObject.code}\`); })); } - public constructor() {} + private constructor() {} } -interface __Options_Index { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_Index { set storageProp(storageProp: number | undefined) get storageProp(): number | undefined @@ -140,7 +129,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -155,9 +144,9 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test storageprop with appstorage', - [storagePropTransform, uiNoRecheck], + [storagePropTransform, uiNoRecheck, recheck], { - checked: [testStoragePropTransformer], + 'checked:ui-no-recheck': [testStoragePropTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts index aa649440b..892c35b0b 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-complex-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,10 +38,6 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test storageprop complex type transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; import { StoragePropDecoratedVariable as StoragePropDecoratedVariable } from "@ohos.arkui.stateManagement"; @@ -228,11 +225,11 @@ final class Status extends BaseEnum { @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { set arrayB(arrayB: Array | undefined) get arrayB(): Array | undefined @@ -266,9 +263,9 @@ interface __Options_MyStateSample { set unionB(unionB: string | undefined | undefined) get unionB(): string | undefined | undefined - set __backing_unionB(__backing_unionB: StoragePropDecoratedVariable | undefined) + set __backing_unionB(__backing_unionB: StoragePropDecoratedVariable | undefined | undefined) - get __backing_unionB(): StoragePropDecoratedVariable | undefined + get __backing_unionB(): StoragePropDecoratedVariable | undefined | undefined set classB(classB: Person | undefined) get classB(): Person | undefined @@ -288,7 +285,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -302,9 +299,9 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test storageprop complex type transform', - [storagePropTransform, uiNoRecheck], + [storagePropTransform, uiNoRecheck, recheck], { - checked: [testStoragePropTransformer], + 'checked:ui-no-recheck': [testStoragePropTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts index c56d42735..92924efb9 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/storageprop/storageprop-primitive-type.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,10 +38,6 @@ const storagePropTransform: Plugins = { const pluginTester = new PluginTester('test storageprop primitive type transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; import { StoragePropDecoratedVariable as StoragePropDecoratedVariable } from "@ohos.arkui.stateManagement"; @@ -98,11 +95,11 @@ function main() {} @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { set numB(numB: number | undefined) get numB(): number | undefined @@ -128,7 +125,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -142,9 +139,9 @@ function testStoragePropTransformer(this: PluginTestContext): void { pluginTester.run( 'test storageprop primitive type transform', - [storagePropTransform, uiNoRecheck], + [storagePropTransform, uiNoRecheck, recheck], { - checked: [testStoragePropTransformer], + 'checked:ui-no-recheck': [testStoragePropTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts index 692bf1f24..83ebe0bcc 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/watch/watch-basic.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../../utils/artkts-config'; +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 } from '../../../../utils/plugins'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; import { uiTransform } from '../../../../../ui-plugins'; import { Plugins } from '../../../../../common/plugin-context'; @@ -37,50 +38,20 @@ const watchTransform: Plugins = { const pluginTester = new PluginTester('test basic watch transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { ConsumeDecoratedVariable as ConsumeDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { ProvideDecoratedVariable as ProvideDecoratedVariable } from "@ohos.arkui.stateManagement"; - -import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; - -import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; - -import { int32 as int32 } from "@koalaui.runtime.common"; - -import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; - -import { setObservationDepth as setObservationDepth } from "@ohos.arkui.stateManagement"; - -import { BackingValue as BackingValue } from "@ohos.arkui.stateManagement"; - -import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; - -import { ObjectLinkDecoratedVariable as ObjectLinkDecoratedVariable } from "@ohos.arkui.stateManagement"; - -import { DecoratedV1VariableBase as DecoratedV1VariableBase } from "@ohos.arkui.stateManagement"; - -import { LinkDecoratedVariable as LinkDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { StoragePropDecoratedVariable as StoragePropDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { StorageLinkDecoratedVariable as StorageLinkDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { PropDecoratedVariable as PropDecoratedVariable } from "@ohos.arkui.stateManagement"; - import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; - +import { IObservedObject as IObservedObject } from "@ohos.arkui.stateManagement"; +import { MutableStateMeta as MutableStateMeta } from "@ohos.arkui.stateManagement"; +import { int32 as int32 } from "@koalaui.runtime.common"; +import { WatchIdType as WatchIdType } from "@ohos.arkui.stateManagement"; +import { SubscribedWatches as SubscribedWatches } from "@ohos.arkui.stateManagement"; import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Entry as Entry } from "@ohos.arkui.component"; - import { State as State, Prop as Prop, StorageLink as StorageLink, StorageProp as StorageProp, Link as Link, Watch as Watch, ObjectLink as ObjectLink, Observed as Observed, Track as Track, Provide as Provide, Consume as Consume } from "@ohos.arkui.stateManagement"; function main() {} @@ -221,10 +192,10 @@ function main() {} @memo() public _build(@memo() style: ((instance: MyStateSample)=> MyStateSample) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_MyStateSample | undefined): void { Child._instantiateImpl(undefined, (() => { return new Child(); - }), undefined, undefined, undefined); + })); } - public constructor() {} + private constructor() {} } @@ -235,11 +206,11 @@ function main() {} @memo() public _build(@memo() style: ((instance: Child)=> Child) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Child | undefined): void {} - public constructor() {} + private constructor() {} } -interface __Options_MyStateSample { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { set statevar(statevar: string | undefined) get statevar(): string | undefined @@ -273,7 +244,7 @@ interface __Options_MyStateSample { } -interface __Options_Child { +@Component({freezeWhenInactive:false}) interface __Options_Child { } @@ -281,7 +252,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { MyStateSample._instantiateImpl(undefined, (() => { return new MyStateSample(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -296,9 +267,9 @@ function testWatchTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic watch transform', - [watchTransform, uiNoRecheck], + [watchTransform, uiNoRecheck, recheck], { - checked: [testWatchTransformer], + 'checked:ui-no-recheck': [testWatchTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/ut/ui-plugins/xcomponent/xcomponent-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/xcomponent/xcomponent-basic.test.ts index 46686c1e6..58e9d3629 100644 --- a/arkui-plugins/test/ut/ui-plugins/xcomponent/xcomponent-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/xcomponent/xcomponent-basic.test.ts @@ -14,11 +14,12 @@ */ import * as path from 'path'; -import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; -import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; +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 } from '../../../utils/plugins'; +import { recheck, uiNoRecheck } from '../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../utils/shared-types'; import { uiTransform } from '../../../../ui-plugins'; import { Plugins } from '../../../../common/plugin-context'; @@ -32,25 +33,15 @@ buildConfig.compileFiles = [ const xcomponentTransform: Plugins = { name: 'xcomponent', parsed: uiTransform().parsed, -} +}; const pluginTester = new PluginTester('test basic XComponent transform', buildConfig); const expectedScript: string = ` -import { __memo_id_type as __memo_id_type } from "@ohos.arkui.stateManagement"; - -import { __memo_context_type as __memo_context_type } from "@ohos.arkui.stateManagement"; - import { memo as memo } from "@ohos.arkui.stateManagement"; - -import { UIXComponentAttribute as UIXComponentAttribute } from "@ohos.arkui.component"; - import { UIFlexAttribute as UIFlexAttribute } from "@ohos.arkui.component"; - import { EntryPoint as EntryPoint } from "@ohos.arkui.component"; - import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; - import { Component as Component, Flex as Flex, XComponent as XComponent, FlexDirection as FlexDirection, XComponentType as XComponentType, Entry as Entry, XComponentController as XComponentController, ItemAlign as ItemAlign, FlexAlign as FlexAlign, XComponentParameter as XComponentParameter } from "@ohos.arkui.component"; function main() {} @@ -89,15 +80,15 @@ function main() {} type: XComponentType.TEXTURE, libraryname: "nativerender", controller: (this).myXComponentController, - } as XComponentParameter), "", undefined); + } as XComponentParameter), ""); })); } - public constructor() {} + private constructor() {} } -interface __Options_Index { +@Entry({useSharedStorage:false,storage:"",routeName:""}) @Component({freezeWhenInactive:false}) interface __Options_Index { set myXComponentController(myXComponentController: XComponentController | undefined) get myXComponentController(): XComponentController | undefined @@ -108,7 +99,7 @@ class __EntryWrapper extends EntryPoint { @memo() public entry(): void { Index._instantiateImpl(undefined, (() => { return new Index(); - }), undefined, undefined, undefined); + })); } public constructor() {} @@ -122,9 +113,9 @@ function testXComponentTransformer(this: PluginTestContext): void { pluginTester.run( 'test basic XComponent transform', - [xcomponentTransform, uiNoRecheck], + [xcomponentTransform, uiNoRecheck, recheck], { - checked: [testXComponentTransformer], + 'checked:ui-no-recheck': [testXComponentTransformer], }, { stopAfter: 'checked', diff --git a/arkui-plugins/test/utils/artkts-config.ts b/arkui-plugins/test/utils/artkts-config.ts index 3474c59a2..ad1751edd 100644 --- a/arkui-plugins/test/utils/artkts-config.ts +++ b/arkui-plugins/test/utils/artkts-config.ts @@ -22,18 +22,19 @@ import { ensurePathExists, getFileName, getRootPath, + MOCK_DEP_ANALYZER_PATH, MOCK_ENTRY_DIR_PATH, MOCK_ENTRY_FILE_NAME, - MOCK_LOCAL_SDK_DIR_PATH, MOCK_OUTPUT_CACHE_PATH, MOCK_OUTPUT_DIR_PATH, MOCK_OUTPUT_FILE_NAME, PANDA_SDK_STDLIB_PATH, - RUNTIME_API_PATH, STDLIB_ESCOMPAT_PATH, STDLIB_PATH, STDLIB_STD_PATH, } from './path-config'; +import { ArkTSConfigContextCache } from './cache'; +import { BuildConfig, CompileFileInfo, DependentModule } from './shared-types'; export interface ArkTSConfigObject { compilerOptions: { @@ -45,15 +46,6 @@ export interface ArkTSConfigObject { }; } -export interface CompileFileInfo { - fileName: string; - filePath: string; - dependentFiles: string[]; - abcFilePath: string; - arktsConfigFile: string; - stdLibPath: string; -} - export interface ModuleInfo { isMainModule: boolean; packageName: string; @@ -65,41 +57,10 @@ export interface ModuleInfo { dependencies?: string[]; } -export interface DependentModule { - packageName: string; - moduleName: string; - moduleType: string; - modulePath: string; - sourceRoots: string[]; - entryFile: string; -} - -export type ModuleType = 'har' | string; // TODO: module type unclear - -export interface DependentModule { - packageName: string; - moduleName: string; - moduleType: ModuleType; - modulePath: string; - sourceRoots: string[]; - entryFile: string; -} - -export interface BuildConfig { - packageName: string; - compileFiles: string[]; - loaderOutPath: string; - cachePath: string; - pandaSdkPath: string; - buildSdkPath: string; - sourceRoots: string[]; - moduleRootPath: string; - dependentModuleList: DependentModule[]; -} - export interface ArktsConfigBuilder { buildConfig: BuildConfig; entryFiles: Set; + compileFiles: Map; outputDir: string; cacheDir: string; pandaSdkPath: string; @@ -112,6 +73,8 @@ export interface ArktsConfigBuilder { mergedAbcFile: string; // logger: Logger; // TODO isDebug: boolean; + + clear(): void; } function writeArkTSConfigFile( @@ -158,21 +121,6 @@ function getDependentModules(moduleInfo: ModuleInfo, moduleInfoMap: Map) { - const items = fs.readdirSync(currentDir); - for (const item of items) { - const itemPath = path.join(currentDir, item); - const stat = fs.statSync(itemPath); - - if (stat.isFile()) { - const basename = path.basename(item, '.d.ets'); - pathSection[basename] = [changeFileExtension(itemPath, '', '.d.ets')]; - } else if (stat.isDirectory()) { - traverse(itemPath, pathSection); - } - } -} - function traverseSDK(currentDir: string, pathSection: Record, prefix?: string) { const items = fs.readdirSync(currentDir); @@ -204,6 +152,7 @@ function mockBuildConfig(): BuildConfig { cachePath: path.resolve(getRootPath(), MOCK_OUTPUT_CACHE_PATH), pandaSdkPath: global.PANDA_SDK_PATH, buildSdkPath: global.API_PATH, + depAnalyzerPath: path.resolve(global.PANDA_SDK_PATH, MOCK_DEP_ANALYZER_PATH), sourceRoots: [getRootPath()], moduleRootPath: path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH), dependentModuleList: [], @@ -211,8 +160,10 @@ function mockBuildConfig(): BuildConfig { } class MockArktsConfigBuilder implements ArktsConfigBuilder { + hashId: string; buildConfig: BuildConfig; entryFiles: Set; + compileFiles: Map; outputDir: string; cacheDir: string; pandaSdkPath: string; @@ -225,7 +176,9 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { mergedAbcFile: string; isDebug: boolean; - constructor(buildConfig?: BuildConfig) { + constructor(hashId: string, buildConfig?: BuildConfig) { + this.hashId = hashId; + const _buildConfig: BuildConfig = buildConfig ?? mockBuildConfig(); this.buildConfig = _buildConfig; this.entryFiles = new Set(_buildConfig.compileFiles as string[]); @@ -239,11 +192,20 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { this.dependentModuleList = _buildConfig.dependentModuleList as DependentModule[]; this.isDebug = true; + this.compileFiles = new Map(); this.moduleInfos = new Map(); this.mergedAbcFile = path.resolve(this.outputDir, MOCK_OUTPUT_FILE_NAME); this.generateModuleInfos(); this.generateArkTSConfigForModules(); + this.cacheArkTSConfig(); + } + + private cacheArkTSConfig(): void { + const mainModuleInfo: ModuleInfo = this.moduleInfos.get(this.moduleRootPath)!; + const arktsConfigFile: string = mainModuleInfo.arktsConfigFile; + const compileFiles: Map = this.compileFiles; + ArkTSConfigContextCache.getInstance().set(this.hashId, { arktsConfigFile, compileFiles }); } private generateModuleInfos(): void { @@ -256,7 +218,7 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { moduleRootPath: this.moduleRootPath, sourceRoots: this.sourceRoots, entryFile: '', - arktsConfigFile: path.resolve(this.cacheDir, this.packageName, ARKTS_CONFIG_FILE_PATH), + arktsConfigFile: path.resolve(this.cacheDir, this.hashId, this.packageName, ARKTS_CONFIG_FILE_PATH), compileFileInfos: [], }; this.moduleInfos.set(this.moduleRootPath, mainModuleInfo); @@ -270,7 +232,7 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { moduleRootPath: module.modulePath, sourceRoots: module.sourceRoots, entryFile: module.entryFile, - arktsConfigFile: path.resolve(this.cacheDir, module.packageName, ARKTS_CONFIG_FILE_PATH), + arktsConfigFile: path.resolve(this.cacheDir, this.hashId, module.packageName, ARKTS_CONFIG_FILE_PATH), compileFileInfos: [], }; this.moduleInfos.set(module.modulePath, moduleInfo); @@ -282,6 +244,7 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { const filePathFromModuleRoot: string = path.relative(modulePath, _file); const filePathInCache: string = path.join( this.cacheDir, + this.hashId, moduleInfo.packageName, filePathFromModuleRoot ); @@ -296,6 +259,9 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { stdLibPath: path.resolve(this.pandaSdkPath, PANDA_SDK_STDLIB_PATH, STDLIB_PATH), }; moduleInfo.compileFileInfos.push(fileInfo); + if (!this.compileFiles.has(_file)) { + this.compileFiles.set(_file, fileInfo); + } return; } } @@ -329,6 +295,10 @@ class MockArktsConfigBuilder implements ArktsConfigBuilder { dependenciesSection.push(depModuleInfo.arktsConfigFile); }); } + + clear(): void { + ArkTSConfigContextCache.getInstance().delete(this.hashId); + } } export { mockBuildConfig, MockArktsConfigBuilder }; diff --git a/arkui-plugins/test/utils/cache.ts b/arkui-plugins/test/utils/cache.ts index b24fcdf64..06942d1c4 100644 --- a/arkui-plugins/test/utils/cache.ts +++ b/arkui-plugins/test/utils/cache.ts @@ -13,21 +13,15 @@ * limitations under the License. */ +import { ArkTSConfigContext, FileDependencyContext, PluginTestContext } from './shared-types'; + class TesterCache { private cacheInfo: Map; - private static instance: TesterCache; - private constructor() { + constructor() { this.cacheInfo = new Map(); } - static getInstance(): TesterCache { - if (!this.instance) { - this.instance = new TesterCache(); - } - return this.instance; - } - public delete(key: string) { if (this.cacheInfo.has(key)) { this.cacheInfo.delete(key); @@ -56,4 +50,37 @@ class TesterCache { } } -export { TesterCache }; +class PluginTestContextCache extends TesterCache { + private static _instance: TesterCache; + + static getInstance(): TesterCache { + if (!this._instance) { + this._instance = new PluginTestContextCache(); + } + return this._instance; + } +} + +class ArkTSConfigContextCache extends TesterCache { + private static _instance: TesterCache; + + static getInstance(): TesterCache { + if (!this._instance) { + this._instance = new ArkTSConfigContextCache(); + } + return this._instance; + } +} + +class FileDependencyContextCache extends TesterCache { + private static _instance: TesterCache; + + static getInstance(): TesterCache { + if (!this._instance) { + this._instance = new FileDependencyContextCache(); + } + return this._instance; + } +} + +export { TesterCache, PluginTestContextCache, ArkTSConfigContextCache, FileDependencyContextCache }; diff --git a/arkui-plugins/test/utils/compile.ts b/arkui-plugins/test/utils/compile.ts index f893dae3b..4d4495909 100644 --- a/arkui-plugins/test/utils/compile.ts +++ b/arkui-plugins/test/utils/compile.ts @@ -13,48 +13,191 @@ * limitations under the License. */ -import { PluginDriver } from './plugin-driver'; -import { PluginContext, PluginExecutor } from '../../common/plugin-context'; -import { EtsglobalRemover } from '../../common/etsglobal-remover'; import * as arkts from '@koalaui/libarkts'; +import EventEmitter from 'events'; +import type { JobInfo, PluginTestContext, ProcessEvent, TraceOptions } from './shared-types'; +import { MockPluginDriver, stateName } from './plugin-driver'; +import { createCacheContextFromFile, destroyContext, resetConfig } from './global'; +import { PluginDriver } from './plugin-driver'; +import { PluginState, PluginContext, PluginExecutor } from '../../common/plugin-context'; -function restartCompilerUptoState(state: arkts.Es2pandaContextState, restart: boolean): boolean { - try { - const ast: arkts.EtsScript | undefined = arkts.EtsScript.fromContext(); - if (!ast) { - return false; - } +function insertPlugin(driver: PluginDriver, plugin: PluginExecutor | undefined): boolean { + const pluginContext: PluginContext = driver.getPluginContext(); + if (plugin) { + plugin.handler.apply(pluginContext); + } + return true; +} - if (restart) { - const srcText = new EtsglobalRemover().visitor(ast).dumpSrc(); - arkts.arktsGlobal.es2panda._DestroyContext(arkts.arktsGlobal.context); - arkts.arktsGlobal.compilerContext = arkts.Context.createFromString(srcText); +function collectPluginTestContext( + context: arkts.Context, + isExternal: boolean, + tracing: TraceOptions +): PluginTestContext { + const pluginTestContext: PluginTestContext = {}; + try { + const program: arkts.Program = arkts.getOrUpdateGlobalContext(context.peer).program; + // TODO: add error/warning handling after plugin + if (!isExternal) { + const script: arkts.EtsScript = program.astNode; + pluginTestContext.scriptSnapshot = script.dumpSrc(); + } else { + const declContexts: Record = {}; + const externalSources: arkts.ExternalSource[] = program.externalSources; + externalSources + .filter((source) => { + const sourceProgram: arkts.Program = source.programs[0]; + return ( + tracing.externalSourceNames.includes(source.getName()) && + sourceProgram && + sourceProgram.isASTLowered() + ); + }) + .forEach((source) => { + const sourceProgram: arkts.Program = source.programs[0]; + const sourceTestContext: PluginTestContext = {}; + const name: string = source.getName(); + const script: arkts.EtsScript = sourceProgram.astNode; + const scriptSnapshot = script.dumpSrc(); + sourceTestContext.scriptSnapshot = scriptSnapshot; + declContexts[name] = sourceTestContext; + }); + pluginTestContext.declContexts = declContexts; } - - arkts.proceedToState(state); - return true; } catch (e) { - return false; + // Do nothing + } finally { + return pluginTestContext; } } -function insertPlugin( - driver: PluginDriver, - plugin: PluginExecutor | undefined, - state: arkts.Es2pandaContextState +/** + * @param emitter event emitter. + * @param jobId job id. + * @param state the current state. + * @param context context for the single file. + * @param isExternal boolean indicates if plugin is compiling external sources. + * @param stopAfter state that should stop after running plugins. + * @returns boolean indicates whether should proceed to the next state. + */ +function runPluginsAtState( + emitter: EventEmitter, + jobId: string, + state: arkts.Es2pandaContextState, + context: arkts.Context, + isExternal: boolean, + tracing: TraceOptions, + stopAfter?: PluginState ): boolean { - arkts.proceedToState(state); - const pluginContext: PluginContext = driver.getPluginContext(); - const ast: arkts.EtsScript | undefined = arkts.EtsScript.fromContext(); + const stateStr = stateName(state); + const plugins = MockPluginDriver.getInstance().getSortedPlugins(state); + if (plugins && plugins.length > 0) { + plugins.forEach((plugin) => { + insertPlugin(MockPluginDriver.getInstance(), plugin); + const pluginName: string = plugin.name; + const pluginStateId: `${PluginState}:${string}` = `${stateStr}:${pluginName}`; + const pluginTestContext = collectPluginTestContext(context, isExternal, tracing); + emitter.emit('TASK_COLLECT', { + jobId, + pluginStateId, + pluginTestContext: pluginTestContext, + }); + }); + } + const pluginStateId: PluginState = `${stateStr}`; + const pluginTestContext = collectPluginTestContext(context, isExternal, tracing); + emitter.emit('TASK_COLLECT', { + jobId, + pluginStateId, + pluginTestContext: pluginTestContext, + }); + return !!stopAfter && stopAfter === stateStr; +} + +function compileAbc(emitter: EventEmitter, jobInfo: JobInfo, tracing: TraceOptions): void { + MockPluginDriver.getInstance().initPlugins(jobInfo.plugins ?? []); - if (!ast) { - return false; + const fileInfo = jobInfo.compileFileInfo!; + const globalContextPtr = jobInfo.globalContextPtr!; + + const ets2pandaCmd = [ + '_', + '--extension', + 'ets', + '--arktsconfig', + fileInfo.arktsConfigFile, + '--output', + fileInfo.abcFilePath, + ]; + ets2pandaCmd.push(fileInfo.filePath); + + const config = resetConfig(ets2pandaCmd); + const context = createCacheContextFromFile(config, fileInfo.filePath, globalContextPtr, false); + MockPluginDriver.getInstance().getPluginContext().setContextPtr(context.peer); + + const stopAfter = jobInfo.stopAfter!; + let shouldStop = false; + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context.peer); + shouldStop = runPluginsAtState( + emitter, + jobInfo.id, + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, + context, + false, + tracing, + stopAfter + ); + if (shouldStop) { + destroyContext(context); + MockPluginDriver.getInstance().clear(); + return; } - if (plugin) { - plugin.handler.apply(pluginContext); + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context.peer); + shouldStop = runPluginsAtState( + emitter, + jobInfo.id, + arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + context, + false, + tracing, + stopAfter + ); + if (shouldStop) { + destroyContext(context); + MockPluginDriver.getInstance().clear(); + return; } - return true; + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, context.peer); + + destroyContext(context); + MockPluginDriver.getInstance().clear(); +} + +function compileExternalProgram(emitter: EventEmitter, jobInfo: JobInfo, tracing: TraceOptions): void { + MockPluginDriver.getInstance().initPlugins(jobInfo.plugins ?? []); + + const fileInfo = jobInfo.compileFileInfo!; + const globalContextPtr = jobInfo.globalContextPtr!; + const ets2pandaCmd = ['-', '--extension', 'ets', '--arktsconfig', fileInfo.arktsConfigFile]; + ets2pandaCmd.push(fileInfo.filePath); + + const config = resetConfig(ets2pandaCmd); + const context = createCacheContextFromFile(config, fileInfo.filePath, globalContextPtr, true); + MockPluginDriver.getInstance().getPluginContext().setContextPtr(context.peer); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context.peer); + runPluginsAtState(emitter, jobInfo.id, arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context, true, tracing); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context.peer); + runPluginsAtState(emitter, jobInfo.id, arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context, true, tracing); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_LOWERED, context.peer); + + destroyContext(context); + MockPluginDriver.getInstance().clear(); } -export { restartCompilerUptoState, insertPlugin }; +export { compileAbc, compileExternalProgram }; diff --git a/arkui-plugins/test/utils/global.ts b/arkui-plugins/test/utils/global.ts index cbccd4afa..99ac287e3 100644 --- a/arkui-plugins/test/utils/global.ts +++ b/arkui-plugins/test/utils/global.ts @@ -13,11 +13,10 @@ * limitations under the License. */ -import * as fs from 'fs'; -import { CompileFileInfo } from './artkts-config'; import * as arkts from '@koalaui/libarkts'; +import { CompileFileInfo } from './shared-types'; -function initGlobal(fileInfo: CompileFileInfo, isDebug: boolean = true): void { +function createGlobalConfig(fileInfo: CompileFileInfo, isDebug: boolean = true): arkts.Config { const config = [ '_', '--extension', @@ -33,11 +32,31 @@ function initGlobal(fileInfo: CompileFileInfo, isDebug: boolean = true): void { } config.push(fileInfo.filePath); + arkts.MemInitialize(); arkts.arktsGlobal.filePath = fileInfo.filePath; - resetConfig(config); + return resetConfig(config); +} + +function destroyGlobalConfig(config: arkts.Config): void { + destroyConfig(config); + arkts.MemFinalize(); +} + +function createGlobalContextPtr(config: arkts.Config, files: string[]): number { + return arkts.CreateGlobalContext(config.peer, files, files.length, false); +} + +function destroyGlobalContextPtr(globalContextPtr: number): void { + arkts.DestroyGlobalContext(globalContextPtr); +} - const source: string = fs.readFileSync(fileInfo.filePath).toString(); - resetContext(source); +function createCacheContextFromFile( + config: arkts.Config, + filePath: string, + globalContextPtr: number, + isExternal: boolean +): arkts.Context { + return arkts.Context.createCacheContextFromFile(config.peer, filePath, globalContextPtr, isExternal); } function resetContext(source: string): void { @@ -51,48 +70,43 @@ function resetContext(source: string): void { } } -function resetConfig(cmd: string[]): void { +function resetConfig(cmd: string[]): arkts.Config { try { arkts.arktsGlobal.config; - destroyConfig(); + destroyConfig(arkts.arktsGlobal.config); } catch (e) { // Do nothing } finally { - const arkTSConfig: arkts.Config = arkts.Config.create(cmd); - arkts.arktsGlobal.config = arkTSConfig.peer; + const config = arkts.Config.create(cmd); + arkts.arktsGlobal.config = config.peer; + return config; } } -function destroyContext(): void { +function destroyContext(context: arkts.Context): void { try { - arkts.arktsGlobal.clearContext(); + arkts.arktsGlobal.es2panda._DestroyContext(context.peer); } catch (e) { // Do nothing } } -function destroyConfig(): void { +function destroyConfig(config: arkts.Config): void { try { - arkts.destroyConfig(arkts.arktsGlobal.config); + arkts.destroyConfig(config); } catch (e) { // Do nothing } } -function canProceedToState(state: arkts.Es2pandaContextState): boolean { - const stateToSkip: arkts.Es2pandaContextState[] = [ - arkts.Es2pandaContextState.ES2PANDA_STATE_SCOPE_INITED, - arkts.Es2pandaContextState.ES2PANDA_STATE_BOUND, - arkts.Es2pandaContextState.ES2PANDA_STATE_LOWERED, - arkts.Es2pandaContextState.ES2PANDA_STATE_ASM_GENERATED, - arkts.Es2pandaContextState.ES2PANDA_STATE_ERROR, - ]; - if (state in stateToSkip) { - return false; - } - - const currState = arkts.arktsGlobal.es2panda._ContextState(arkts.arktsGlobal.context); - return currState < state; -} - -export { initGlobal, resetContext, resetConfig, destroyContext, destroyConfig, canProceedToState }; +export { + createGlobalConfig, + destroyGlobalConfig, + createGlobalContextPtr, + destroyGlobalContextPtr, + createCacheContextFromFile, + resetContext, + resetConfig, + destroyContext, + destroyConfig, +}; diff --git a/arkui-plugins/test/local/@ohos.arkui.component.enums.d.ets b/arkui-plugins/test/utils/hash-generator.ts similarity index 36% rename from arkui-plugins/test/local/@ohos.arkui.component.enums.d.ets rename to arkui-plugins/test/utils/hash-generator.ts index e72c21ace..09e0b6d45 100644 --- a/arkui-plugins/test/local/@ohos.arkui.component.enums.d.ets +++ b/arkui-plugins/test/utils/hash-generator.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 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 @@ -13,41 +13,36 @@ * limitations under the License. */ -export declare enum FlexAlign { - Start = 0, - Center = 1, - End = 2, - SpaceBetween = 3, - SpaceAround = 4, - SpaceEvenly = 5 -} +import { randomBytes } from 'crypto'; +import { getCommonPath } from '../../path'; +const common = require(getCommonPath()); +const UniqueId = common.UniqueId; -export declare enum HorizontalAlign { - Start = 0, - Center = 1, - End = 2 -} +export class HashGenerator { + static instance: HashGenerator; -export declare enum IlluminatedType { - NONE = 0, - BORDER = 1, - CONTENT = 2, - BORDER_CONTENT = 3, - BLOOM_BORDER = 4, - BLOOM_BORDER_CONTENT = 5 -} + private constructor() {} + + static getInstance(): HashGenerator { + if (!this.instance) { + this.instance = new HashGenerator(); + } -export declare enum Color { - White = 0, - Black = 1, - Blue = 2, - Brown = 3, - Gray = 4, - Green = 5, - Grey = 6, - Orange = 7, - Pink = 8, - Red = 9, - Yellow = 10, - Transparent = 11 -} \ No newline at end of file + return this.instance; + } + + dynamicSha1Id(id: string, length: number = 7): string { + const uniqId = new UniqueId(); + uniqId.addString('hashId'); + uniqId.addString(id); + uniqId.addString(randomBytes(length).toString('hex')); + return uniqId.compute().substring(0, length); + } + + staticSha1Id(id: string, length: number = 7): string { + const uniqId = new UniqueId(); + uniqId.addString('hashId'); + uniqId.addString(id); + return uniqId.compute().substring(0, length); + } +} diff --git a/arkui-plugins/test/utils/path-config.ts b/arkui-plugins/test/utils/path-config.ts index 608df6dee..4712832cf 100644 --- a/arkui-plugins/test/utils/path-config.ts +++ b/arkui-plugins/test/utils/path-config.ts @@ -16,24 +16,25 @@ import * as fs from 'fs'; import * as path from 'path'; -export const ARKTS_CONFIG_FILE_PATH: string = 'arktsconfig.json'; -export const PANDA_SDK_PATH: string = 'node_modules/@panda/sdk'; +export const ARKTS_CONFIG_FILE_PATH: string = 'arktsconfig.json';; export const PANDA_SDK_STDLIB_PATH: string = 'lib'; export const STDLIB_PATH: string = 'stdlib'; export const STDLIB_STD_PATH: string = 'stdlib/std'; export const STDLIB_ESCOMPAT_PATH: string = 'stdlib/escompat'; -export const RUNTIME_API_PATH: string = 'demo/runtime-api'; export const MOCK_ENTRY_DIR_PATH: string = 'demo/mock'; export const MOCK_ENTRY_FILE_NAME: string = 'entry.ets'; export const MOCK_OUTPUT_CACHE_PATH: string = 'generated/cache'; export const MOCK_OUTPUT_DIR_PATH: string = 'generated/abc'; export const MOCK_OUTPUT_FILE_NAME: string = 'entry.abc'; -export const MOCK_LOCAL_SDK_DIR_PATH: string = 'local'; +export const MOCK_DEP_ANALYZER_PATH: string = 'bin/dependency_analyzer'; +export const MOCK_FILE_DEP_FILE_NAME: string = 'file_dependencies.json'; +export const MOCK_DEP_INPUT_FILE_NAME: string = 'depInput.txt'; export const ETS_SUFFIX: string = '.ets'; export const ABC_SUFFIX: string = '.abc'; +export const DECL_ETS_SUFFIX: string = '.d.ets'; function getRootPath(): string { - return path.resolve(__dirname, '..'); + return path.resolve(__dirname, '..', '..', 'test'); } function changeFileExtension(file: string, targetExt: string, originExt = ''): string { diff --git a/arkui-plugins/test/utils/plugin-driver.ts b/arkui-plugins/test/utils/plugin-driver.ts index 46ce7f562..451ecff9d 100644 --- a/arkui-plugins/test/utils/plugin-driver.ts +++ b/arkui-plugins/test/utils/plugin-driver.ts @@ -21,6 +21,8 @@ export interface PluginDriver { initPlugins(plugins: Plugins[]): void; getSortedPlugins(state: arkts.Es2pandaContextState): PluginExecutor[] | undefined; getPluginContext(): PluginContext; + getPluginHistory(): (PluginState | `${PluginState}:${string}`)[]; + clear(): void; } function toCamelCase(str: string): string { @@ -71,25 +73,45 @@ function selectPlugins(plugins: Plugins[], stage: PluginState): PluginExecutor[] class MockPluginDriver implements PluginDriver { private sortedPlugins: Map; - private context: PluginContext; + private history: Set; + private context: PluginContext | undefined; + + private static instance: PluginDriver | undefined; constructor() { this.sortedPlugins = new Map(); + this.history = new Set(); this.context = new PluginContext(); } + public static getInstance(): PluginDriver { + if (!this.instance) { + this.instance = new MockPluginDriver(); + } + return this.instance; + } + + private collectHistory(state: PluginState, plugins: PluginExecutor[]) { + for (const plugin of plugins) { + this.history.add(`${state}:${plugin.name}`); + } + this.history.add(state); + } + public initPlugins(plugins: Plugins[]): void { const pluginsByState = new Map(); Object.values(arkts.Es2pandaContextState) .filter(isNumber) .forEach((it) => { - const selected = selectPlugins(plugins, stateName(it)); + const state = stateName(it); + const selected = selectPlugins(plugins, state); if (selected.length > 0) { pluginsByState.set(it, selected); } else { pluginsByState.set(it, undefined); } + this.collectHistory(state, selected); }); this.sortedPlugins = pluginsByState; @@ -100,8 +122,20 @@ class MockPluginDriver implements PluginDriver { } public getPluginContext(): PluginContext { + if (!this.context) { + this.context = new PluginContext(); + } return this.context; } + + public getPluginHistory(): (PluginState | `${PluginState}:${string}`)[] { + return Array.from(this.history); + } + + public clear(): void { + this.sortedPlugins.clear(); + this.context = undefined; + } } export { stateName, MockPluginDriver }; diff --git a/arkui-plugins/test/utils/plugin-tester.ts b/arkui-plugins/test/utils/plugin-tester.ts index 710456e21..78684a1f2 100644 --- a/arkui-plugins/test/utils/plugin-tester.ts +++ b/arkui-plugins/test/utils/plugin-tester.ts @@ -13,22 +13,14 @@ * limitations under the License. */ -import { ArktsConfigBuilder, BuildConfig, CompileFileInfo, MockArktsConfigBuilder, ModuleInfo } from './artkts-config'; -import { MockPluginDriver, PluginDriver, stateName } from './plugin-driver'; -import { isNumber } from './safe-types'; -import { - canProceedToState, - destroyConfig, - destroyContext, - initGlobal, - resetConfig, - resetContext, -} from './global'; -import { insertPlugin } from './compile'; -import { PluginExecutor, Plugins, PluginState } from '../../common/plugin-context'; -import { TesterCache } from './cache'; import * as arkts from '@koalaui/libarkts'; -import * as fs from 'fs'; +import { ArktsConfigBuilder, MockArktsConfigBuilder, ModuleInfo } from './artkts-config'; +import { MockPluginDriver } from './plugin-driver'; +import { BuildConfig, CompileFileInfo, TraceOptions } from './shared-types'; +import { HashGenerator } from './hash-generator'; +import { TaskProcessor } from './task-processor'; +import { PluginTestContextCache } from './cache'; +import { Plugins, PluginState } from '../../common/plugin-context'; type TestParams = Parameters; @@ -44,134 +36,112 @@ type TestHooks = { afterEach?: Parameters; }; -export interface PluginTestContext { - scriptSnapshot?: string; - errors?: string[]; - warnings?: string[]; -} +const TEST_ALLOWED_STATES: arkts.Es2pandaContextState[] = [ + arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, + arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, + arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, +]; export interface PluginTesterOptions { stopAfter: PluginState; buildConfig?: BuildConfig; + tracing?: TraceOptions; } class PluginTester { - private configBuilder: ArktsConfigBuilder; - private pluginDriver: PluginDriver; + private hashId: string; private describe: string; - private cache: TesterCache; + private configBuilder: ArktsConfigBuilder; + private taskProcessor?: TaskProcessor; + private resolve?: Promise; constructor(describe: string, buildConfig?: BuildConfig) { this.describe = describe; - this.configBuilder = new MockArktsConfigBuilder(buildConfig); - this.pluginDriver = new MockPluginDriver(); - this.cache = TesterCache.getInstance(); + this.hashId = HashGenerator.getInstance().dynamicSha1Id(describe, 13); + this.configBuilder = new MockArktsConfigBuilder(this.hashId, buildConfig); + } + + private clear(): void { + this.clearCache(); + this.configBuilder.clear(); + this.taskProcessor?.clear(); + MockPluginDriver.getInstance().clear(); + } + + private clearCache(): void { + const pluginHistory = MockPluginDriver.getInstance().getPluginHistory(); + for (const pluginStateId of pluginHistory) { + const abcKey = this.getCacheKey(pluginStateId); + const externalKey = this.getCacheKey(pluginStateId, true); + PluginTestContextCache.getInstance().delete(abcKey); + PluginTestContextCache.getInstance().delete(externalKey); + } } - private loadPluginDriver(plugins: Plugins[]): void { - this.pluginDriver.initPlugins(plugins); + private getCacheKey(pluginStateId: PluginState | `${PluginState}:${string}`, isExternal?: boolean) { + return [this.hashId, !!isExternal ? 'external' : 'abc', pluginStateId].join(':'); } private test( - key: PluginState | `${PluginState}:${string}`, - index: arkts.Es2pandaContextState, + pluginStateId: PluginState | `${PluginState}:${string}`, testName: string, - pluginHooks: PluginTestHooks, - plugin?: PluginExecutor + pluginHooks: PluginTestHooks ): void { - let cached: boolean = false; - const cacheKey: string = `${testName}-${key}`; - if (index > arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED) { - return; - } - if (canProceedToState(index)) { - arkts.proceedToState(index); - } - if (plugin) { - insertPlugin(this.pluginDriver, plugin, index); - this.captureContext(cacheKey); - cached = true; - } - const hook: SkipFirstParam | undefined = pluginHooks[key]; + const hook: SkipFirstParam | undefined = pluginHooks[pluginStateId]; if (!!hook) { - if (!cached) this.captureContext(cacheKey); - test(testName, hook[0]?.bind(this.cache.get(cacheKey)), hook[1]); - } - } - - private captureContext(cacheKey: string): void { - try { - // TODO: add error/warning handling after plugin - const context: PluginTestContext = this.cache.get(cacheKey) ?? {}; - const script: arkts.EtsScript = arkts.EtsScript.fromContext(); - context.scriptSnapshot = script.dumpSrc(); - this.cache.set(cacheKey, context); - } catch (e) { - // Do nothing + const that = this; + test( + testName, + async () => { + let context; + await that.resolve?.then(async () => { + const abcKey = this.getCacheKey(pluginStateId); + const externalKey = this.getCacheKey(pluginStateId, true); + const abcTestContext = PluginTestContextCache.getInstance().get(abcKey); + const externalTestContext = PluginTestContextCache.getInstance().get(externalKey); + context = { ...abcTestContext, ...externalTestContext }; + }); + hook[0]?.bind(context)(undefined as any); + }, + hook[1] + ); } } - private proceedToState( - state: PluginState, - index: arkts.Es2pandaContextState, + private pluginTests( + key: PluginState | `${PluginState}:${string}`, testName: string, - pluginHooks: PluginTestHooks, - plugins?: PluginExecutor[] + pluginHooks: PluginTestHooks ): void { - if (plugins && plugins.length > 0) { - plugins.forEach((plugin) => { - const pluginName: string = plugin.name; - const key: `${PluginState}:${string}` = `${state}:${pluginName}`; - this.test(key, index, `[${key}] ${testName}`, pluginHooks, plugin); - }); - } - this.test(state, index, `[${state}] ${testName}`, pluginHooks); + this.test(key, `[${key}] ${testName}`, pluginHooks); } - private singleFileCompile( + private singleFileCompileTests( fileInfo: CompileFileInfo, moduleInfo: ModuleInfo, testName: string, - pluginHooks: PluginTestHooks, - stopAfter: PluginState + pluginHooks: PluginTestHooks ): void { - let shouldStop: boolean = false; - - Object.values(arkts.Es2pandaContextState) - .filter(isNumber) - .forEach((it) => { - if (shouldStop) { - return; - } - const state: PluginState = stateName(it); - const plugins: PluginExecutor[] | undefined = this.pluginDriver.getSortedPlugins(it); - this.proceedToState( - state, - it, - `${moduleInfo.packageName} - ${fileInfo.fileName}: ${testName}`, - pluginHooks, - plugins - ); - shouldStop = state === stopAfter; - }); + const name: string = `${moduleInfo.packageName} - ${fileInfo.fileName}: ${testName}`; + const history = MockPluginDriver.getInstance().getPluginHistory(); + history.forEach((key) => { + this.pluginTests(key, name, pluginHooks); + }); } - private traverseFile(testName: string, pluginHooks: PluginTestHooks, stopAfter: PluginState): void { - let once: boolean = false; + private compileTests(testName: string, pluginHooks: PluginTestHooks): void { this.configBuilder.moduleInfos.forEach((moduleInfo) => { moduleInfo.compileFileInfos.forEach((fileInfo) => { - if (!once) { - initGlobal(fileInfo, this.configBuilder.isDebug); - once = true; - } else { - const source: string = fs.readFileSync(fileInfo.filePath).toString(); - resetContext(source); - } - this.singleFileCompile(fileInfo, moduleInfo, testName, pluginHooks, stopAfter); + this.singleFileCompileTests(fileInfo, moduleInfo, testName, pluginHooks); }); }); } + private async compile(plugins: Plugins[], stopAfter?: PluginState, tracing?: TraceOptions): Promise { + this.taskProcessor = new TaskProcessor(this.hashId, this.configBuilder.buildConfig); + return this.taskProcessor.invokeWorkers(plugins, stopAfter); + } + run( testName: string, plugins: Plugins[], @@ -180,12 +150,9 @@ class PluginTester { testHooks?: TestHooks ): void { if (!!options.buildConfig) { - this.configBuilder = new MockArktsConfigBuilder(options.buildConfig); + this.configBuilder = new MockArktsConfigBuilder(this.hashId, options.buildConfig); } - this.cache.clear(); - this.loadPluginDriver(plugins); - const that = this; describe(this.describe, () => { if (testHooks?.beforeAll) { @@ -197,11 +164,13 @@ class PluginTester { if (testHooks?.afterEach) { afterEach(...testHooks.afterEach); } + afterAll(() => { - destroyContext(); - destroyConfig(); + that.clear(); }); - that.traverseFile(testName, pluginHooks, options.stopAfter); + + that.resolve = that.compile(plugins, options.stopAfter); + that.compileTests(testName, pluginHooks); }); } } diff --git a/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts b/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts index 69e2b23ad..f7d060b9f 100644 --- a/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts +++ b/arkui-plugins/test/utils/plugins/builder-lambda-no-recheck.ts @@ -26,7 +26,7 @@ export const builderLambdaNoRecheck: Plugins = { name: 'builder-lambda-no-recheck', checked(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; @@ -40,7 +40,6 @@ export const builderLambdaNoRecheck: Plugins = { }); program = programVisitor.programVisitor(program); script = program.astNode; - arkts.GlobalInfo.getInfoInstance().reset(); return script; } return script; diff --git a/arkui-plugins/test/utils/plugins/memo-no-recheck.ts b/arkui-plugins/test/utils/plugins/memo-no-recheck.ts index ff018cec5..c953249a1 100644 --- a/arkui-plugins/test/utils/plugins/memo-no-recheck.ts +++ b/arkui-plugins/test/utils/plugins/memo-no-recheck.ts @@ -29,7 +29,7 @@ import { FunctionTransformer } from '../../../memo-plugins/function-transformer' export const memoNoRecheck: Plugins = { name: 'memo-no-recheck', checked(this: PluginContext): arkts.EtsScript | undefined { - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; let script = program.astNode; diff --git a/arkui-plugins/test/utils/plugins/recheck.ts b/arkui-plugins/test/utils/plugins/recheck.ts index 085d3731e..2c3559df4 100644 --- a/arkui-plugins/test/utils/plugins/recheck.ts +++ b/arkui-plugins/test/utils/plugins/recheck.ts @@ -23,7 +23,7 @@ export const recheck: Plugins = { name: 'recheck', checked(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; diff --git a/arkui-plugins/test/utils/plugins/struct-no-recheck.ts b/arkui-plugins/test/utils/plugins/struct-no-recheck.ts index c564b71c7..87a7bdbd0 100644 --- a/arkui-plugins/test/utils/plugins/struct-no-recheck.ts +++ b/arkui-plugins/test/utils/plugins/struct-no-recheck.ts @@ -26,7 +26,7 @@ export const structNoRecheck: Plugins = { name: 'struct-no-recheck', checked(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; @@ -40,7 +40,6 @@ export const structNoRecheck: Plugins = { }); program = programVisitor.programVisitor(program); script = program.astNode; - arkts.GlobalInfo.getInfoInstance().reset(); return script; } return script; diff --git a/arkui-plugins/test/utils/plugins/struct-to-component.ts b/arkui-plugins/test/utils/plugins/struct-to-component.ts index 14d494c05..79c4d6c2e 100644 --- a/arkui-plugins/test/utils/plugins/struct-to-component.ts +++ b/arkui-plugins/test/utils/plugins/struct-to-component.ts @@ -26,7 +26,7 @@ export const structToComponent: Plugins = { name: 'struct-to-component', parsed(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; diff --git a/arkui-plugins/test/utils/plugins/ui-no-recheck.ts b/arkui-plugins/test/utils/plugins/ui-no-recheck.ts index dec4b5296..5fbc6c3fb 100644 --- a/arkui-plugins/test/utils/plugins/ui-no-recheck.ts +++ b/arkui-plugins/test/utils/plugins/ui-no-recheck.ts @@ -26,7 +26,7 @@ export const uiNoRecheck: Plugins = { name: 'ui-no-recheck', checked(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; @@ -40,7 +40,6 @@ export const uiNoRecheck: Plugins = { }); program = programVisitor.programVisitor(program); script = program.astNode; - arkts.GlobalInfo.getInfoInstance().reset(); return script; } return script; diff --git a/arkui-plugins/test/utils/safe-types.ts b/arkui-plugins/test/utils/safe-types.ts index 728c06501..e622c5081 100644 --- a/arkui-plugins/test/utils/safe-types.ts +++ b/arkui-plugins/test/utils/safe-types.ts @@ -17,4 +17,12 @@ function isNumber(value: any): value is number { return typeof value === `number`; } -export { isNumber }; +function isString(value: any): value is string { + return typeof value === 'string'; +} + +function isBitInt(value: any): value is bigint { + return typeof value === 'bigint'; +} + +export { isNumber, isString, isBitInt }; diff --git a/arkui-plugins/test/local/@ohos.arkui.stateManagement.d.ets b/arkui-plugins/test/utils/serializable.ts similarity index 54% rename from arkui-plugins/test/local/@ohos.arkui.stateManagement.d.ets rename to arkui-plugins/test/utils/serializable.ts index 9cb01ec59..99cd25643 100644 --- a/arkui-plugins/test/local/@ohos.arkui.stateManagement.d.ets +++ b/arkui-plugins/test/utils/serializable.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 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 @@ -13,6 +13,19 @@ * limitations under the License. */ -export * from "@ohos.arkui.stateManagement.common"; -export * from "@ohos.arkui.stateManagement.runtime"; -export * from "@ohos.arkui.stateManagement.storage"; +import { isBitInt } from "./safe-types"; + +function serializable(object: T, ignoreKeys?: string[]): T { + const jsonStr = JSON.stringify(object, (key, value) => { + if (isBitInt(value)) { + return undefined; + } + if (ignoreKeys?.includes(key)) { + return undefined; + } + return value; + }); + return JSON.parse(jsonStr); +} + +export { serializable }; diff --git a/arkui-plugins/test/utils/shared-types.ts b/arkui-plugins/test/utils/shared-types.ts new file mode 100644 index 000000000..4582d4246 --- /dev/null +++ b/arkui-plugins/test/utils/shared-types.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 type { Plugins, PluginState } from '../../common/plugin-context'; + +export interface SingleProgramContext { + scriptSnapshot?: string; + errors?: string[]; + warnings?: string[]; +} + +export interface PluginTestContext extends SingleProgramContext { + declContexts?: Record; +} + +export interface ArkTSConfigContext { + arktsConfigFile: string; + compileFiles: Map; +} + +export interface FileDependencyContext { + depInputFile: string; + fileDepsInfoJson: string; +} + +export interface CompileFileInfo { + fileName: string; + filePath: string; + dependentFiles: string[]; + abcFilePath: string; + arktsConfigFile: string; + stdLibPath: string; +} + +export interface BuildConfig { + packageName: string; + compileFiles: string[]; + loaderOutPath: string; + cachePath: string; + pandaSdkPath: string; + buildSdkPath: string; + depAnalyzerPath: string; + sourceRoots: string[]; + moduleRootPath: string; + dependentModuleList: DependentModule[]; +} + +export type ModuleType = 'har' | string; // TODO: module type unclear + +export interface DependentModule { + packageName: string; + moduleName: string; + moduleType: ModuleType; + modulePath: string; + sourceRoots: string[]; + entryFile: string; +} + +export interface JobInfo { + id: string; + isCompileAbc: boolean; // TODO: change to enum + compileFileInfo?: CompileFileInfo; + buildConfig?: BuildConfig; + plugins?: Plugins[]; + globalContextPtr?: number; + stopAfter?: PluginState; +} + +export interface TraceOptions { + externalSourceNames: string[]; +} + +export interface ProcessTaskFinishEvent { + type: 'TASK_FINISH'; + jobId: string; +} + +export interface ProcessExitEvent { + type: 'EXIT'; +} + +export interface ProcessAssignTaskEvent { + type: 'ASSIGN_TASK'; + jobInfo: JobInfo; +} + +export interface ProcessTaskCollectEvent { + type: 'TASK_COLLECT'; + jobId: string; + pluginStateId: PluginState | `${PluginState}:${string}`; + pluginTestContext: PluginTestContext; +} + +export type ProcessEvents = + | ProcessAssignTaskEvent + | ProcessTaskFinishEvent + | ProcessTaskCollectEvent + | ProcessExitEvent; + +export type ProcessEvent = { + [E in ProcessEvents as E['type']]: Omit[]; +}; diff --git a/arkui-plugins/test/utils/task-processor.ts b/arkui-plugins/test/utils/task-processor.ts new file mode 100644 index 000000000..666519197 --- /dev/null +++ b/arkui-plugins/test/utils/task-processor.ts @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 os from 'os'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as child_process from 'child_process'; +import EventEmitter from 'events'; +import type { + BuildConfig, + CompileFileInfo, + JobInfo, + PluginTestContext, + ProcessEvent, + TraceOptions, +} from './shared-types'; +import { mockBuildConfig } from './artkts-config'; +import { + DECL_ETS_SUFFIX, + ensurePathExists, + getFileName, + MOCK_DEP_INPUT_FILE_NAME, + MOCK_FILE_DEP_FILE_NAME, +} from './path-config'; +import { ArkTSConfigContextCache, FileDependencyContextCache, PluginTestContextCache } from './cache'; +import { HashGenerator } from './hash-generator'; +import { createGlobalConfig, createGlobalContextPtr, destroyGlobalConfig, destroyGlobalContextPtr } from './global'; +import { Plugins, PluginState } from '../../common/plugin-context'; +import { serializable } from './serializable'; +import { compileAbc, compileExternalProgram } from './compile'; + +interface Job { + id: string; + isDeclFile: boolean; + isInCycle?: boolean; + fileList: string[]; + dependencies: string[]; + dependants: string[]; + isAbcJob: boolean; +} + +interface Queues { + externalProgramQueue: Job[]; + abcQueue: Job[]; +} + +interface FileDepsInfo { + dependencies: Record; + dependants: Record; +} + +interface WorkerInfo { + isIdle: boolean; +} + +function getDepAnalyzerCmd( + depAnalyzerPath: string, + depInputFile: string, + entryFiles: Set, + outputFile: string, + arktsConfigFile: string +): string[] { + const depAnalyzerCmd: string[] = [`"${depAnalyzerPath}"`]; + + let depInputContent = ''; + entryFiles.forEach((file: string) => { + depInputContent += file + os.EOL; + }); + fs.writeFileSync(depInputFile, depInputContent); + + depAnalyzerCmd.push(`@"${depInputFile}"`); + depAnalyzerCmd.push(`--output=${outputFile}`); + depAnalyzerCmd.push(`--arktsconfig=${arktsConfigFile}`); + + return depAnalyzerCmd; +} + +function findStronglyConnectedComponents(graph: FileDepsInfo): Map> { + const adjacencyList: Record = {}; + const reverseAdjacencyList: Record = {}; + const allNodes = new Set(); + + for (const node in graph.dependencies) { + allNodes.add(node); + graph.dependencies[node].forEach((dep) => allNodes.add(dep)); + } + for (const node in graph.dependants) { + allNodes.add(node); + graph.dependants[node].forEach((dep) => allNodes.add(dep)); + } + + Array.from(allNodes).forEach((node) => { + adjacencyList[node] = graph.dependencies[node] || []; + reverseAdjacencyList[node] = graph.dependants[node] || []; + }); + + const visited = new Set(); + const order: string[] = []; + + function dfs(node: string) { + visited.add(node); + for (const neighbor of adjacencyList[node]) { + if (!visited.has(neighbor)) { + dfs(neighbor); + } + } + order.push(node); + } + + Array.from(allNodes).forEach((node) => { + if (!visited.has(node)) { + dfs(node); + } + }); + + visited.clear(); + const components = new Map>(); + + function reverseDfs(node: string, component: Set) { + visited.add(node); + component.add(node); + for (const neighbor of reverseAdjacencyList[node]) { + if (!visited.has(neighbor)) { + reverseDfs(neighbor, component); + } + } + } + + for (let i = order.length - 1; i >= 0; i--) { + const node = order[i]; + if (!visited.has(node)) { + const component = new Set(); + reverseDfs(node, component); + if (component.size > 1) { + const sortedFiles = Array.from(component).sort(); + const hashKey = HashGenerator.getInstance().staticSha1Id(sortedFiles.join('|'), 13); + components.set(hashKey, component); + } + } + } + + return components; +} + +function getJobDependencies(fileDeps: string[], cycleFiles: Map): Set { + const depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!cycleFiles.has(file)) { + depJobList.add('0' + file); + } else { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } + }); + + return depJobList; +} + +function getJobDependants(fileDeps: string[], cycleFiles: Map): Set { + let depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!file.endsWith(DECL_ETS_SUFFIX)) { + depJobList.add('1' + file); + } + if (cycleFiles.has(file)) { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } else { + depJobList.add('0' + file); + } + }); + + return depJobList; +} + +function insertJobDependantsButSelf(jobMap: Record, id: string, dependants: Set): Set { + jobMap[id].dependants.forEach((dep) => { + dependants.add(dep); + }); + if (dependants.has(id)) { + dependants.delete(id); + } + return dependants; +} + +function createExternalProgramJob(id: string, fileList: string[], dependencies: Set, isInCycle?: boolean): Job { + return { + id, + fileList, + isDeclFile: true, + isInCycle, + isAbcJob: false, + dependencies: Array.from(dependencies), + dependants: [], + }; +} + +function createAbcJob(id: string, fileList: string[], dependencies: Set, isInCycle?: boolean): Job { + return { + id, + isDeclFile: false, + isInCycle, + isAbcJob: true, + fileList, + dependencies: Array.from(dependencies), + dependants: [], + }; +} + +function addJobToQueues(job: Job, queues: Queues): void { + if (queues.externalProgramQueue.some((j) => j.id === job.id) || queues.abcQueue.some((j) => j.id === job.id)) { + return; + } + if (!job.isAbcJob) { + queues.externalProgramQueue.push(job); + } else { + queues.abcQueue.push(job); + } +} + +class TaskProcessor { + hashId: string; + buildConfig: BuildConfig; + tracing: TraceOptions; + cacheDir: string; + entryFiles: Set; + depAnalyzerPath: string; + depInputFile: string; + fileDepsInfoJson: string; + arktsConfigFile: string; + compileFiles: Map; + jobMap: Record; + jobQueues: Queues; + + readonly emitter: EventEmitter = new EventEmitter(); + // private workerPool: WorkerInfo[] = []; + // private workerMap: Map = new Map(); + private worker!: WorkerInfo; + + constructor(hashId: string, buildConfig?: BuildConfig, tracing?: TraceOptions) { + this.hashId = hashId; + this.tracing = tracing ?? { externalSourceNames: [] }; + + const _buildConfig: BuildConfig = buildConfig ?? mockBuildConfig(); + this.buildConfig = _buildConfig; + this.cacheDir = _buildConfig.cachePath; + this.entryFiles = new Set(_buildConfig.compileFiles as string[]); + this.depAnalyzerPath = _buildConfig.depAnalyzerPath; + this.depInputFile = path.resolve(_buildConfig.cachePath, this.hashId, MOCK_DEP_INPUT_FILE_NAME); + this.fileDepsInfoJson = path.resolve(_buildConfig.cachePath, this.hashId, MOCK_FILE_DEP_FILE_NAME); + this.arktsConfigFile = this.getArktsConfigFile(); + this.compileFiles = this.getCompileFiles(); + + this.generateFileDependencies(); + this.cacheFileDependencies(); + this.jobMap = this.collectCompileJobs(); + this.jobQueues = this.initCompileQueues(); + } + + private cacheFileDependencies(): void { + const depInputFile: string = this.arktsConfigFile; + const fileDepsInfoJson: string = this.fileDepsInfoJson; + FileDependencyContextCache.getInstance().set(this.hashId, { depInputFile, fileDepsInfoJson }); + } + + private getArktsConfigFile(): string { + const arktsConfigFile = ArkTSConfigContextCache.getInstance().get(this.hashId)?.arktsConfigFile; + if (!arktsConfigFile) { + const err = `[${this.hashId}] TaskProcessor cannot get arktsConfigFile`; + console.error(err); + throw new Error(err); + } + return arktsConfigFile; + } + + private getCompileFiles(): Map { + const compileFiles = ArkTSConfigContextCache.getInstance().get(this.hashId)?.compileFiles; + if (!compileFiles) { + const err = `[${this.hashId}] TaskProcessor cannot get compileFiles`; + console.error(err); + throw new Error(err); + } + return compileFiles; + } + + private generateFileDependencies(): void { + ensurePathExists(this.depInputFile); + ensurePathExists(this.fileDepsInfoJson); + const depAnalyzerCmd: string[] = getDepAnalyzerCmd( + this.depAnalyzerPath, + this.depInputFile, + this.entryFiles, + this.fileDepsInfoJson, + this.arktsConfigFile + ); + const depAnalyzerCmdStr: string = depAnalyzerCmd.join(' '); + try { + child_process.execSync(depAnalyzerCmdStr).toString(); + } catch (error) { + const err = `[${this.hashId}] TaskProcessor generateFileDependencies failed: ${error}`; + console.error(err); + throw new Error(err); + } + } + + private collectCompileJobs(): Record { + const data = fs.readFileSync(this.fileDepsInfoJson, 'utf-8'); + if (data.length === 0) { + const err = `[${this.hashId}] TaskProcessor cannot read fileDepsInfoJson`; + console.error(err); + throw new Error(err); + } + const fileDepsInfo: FileDepsInfo = JSON.parse(data) as FileDepsInfo; + Object.keys(fileDepsInfo.dependants).forEach((file) => { + if (!(file in fileDepsInfo.dependencies)) { + fileDepsInfo.dependencies[file] = []; + } + }); + + const cycleGroups = findStronglyConnectedComponents(fileDepsInfo); + const cycleFiles: Map = new Map(); + cycleGroups.forEach((value: Set, key: string) => { + value.forEach((file) => { + cycleFiles.set(file, [key]); + }); + }); + + const jobMap: Record = {}; + Object.entries(fileDepsInfo.dependencies).forEach(([key, value]) => { + const dependencies = getJobDependencies(value, cycleFiles); + + // Create generate abc job + if (!key.endsWith(DECL_ETS_SUFFIX)) { + const abcJobId: string = '1' + key; + jobMap[abcJobId] = createAbcJob(abcJobId, [key], dependencies, cycleFiles.has(key)); + } + + // Create cache external job + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + const fileList: string[] = Array.from(cycleGroups.get(id)!); + if (dependencies.has(id)) { + dependencies.delete(id); + } + jobMap[id] = createExternalProgramJob(id, fileList, dependencies, true); + }); + } else { + const id = '0' + key; + const fileList: string[] = [key]; + if (dependencies.has(id)) { + dependencies.delete(id); + } + jobMap[id] = createExternalProgramJob(id, fileList, dependencies); + } + + // register compileFiles for declaration files + if (key.endsWith(DECL_ETS_SUFFIX)) { + const fileInfo: CompileFileInfo = { + filePath: key, + dependentFiles: [], + abcFilePath: '', + arktsConfigFile: this.arktsConfigFile, + fileName: getFileName(key), + stdLibPath: '', + }; + + if (!this.compileFiles.has(key)) { + this.compileFiles.set(key, fileInfo); + } + } + }); + + Object.entries(fileDepsInfo.dependants).forEach(([key, value]) => { + const dependants = getJobDependants(value, cycleFiles); + + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + jobMap[id].dependants = Array.from(insertJobDependantsButSelf(jobMap, id, dependants)); + }); + } else { + const id = '0' + key; + jobMap[id].dependants = Array.from(insertJobDependantsButSelf(jobMap, id, dependants)); + } + }); + + return jobMap; + } + + private initCompileQueues(): Queues { + const queues: Queues = { externalProgramQueue: [], abcQueue: [] }; + Object.values(this.jobMap).forEach((job) => { + if (job.dependencies.length === 0) { + addJobToQueues(job, queues); + } + }); + return queues; + } + + private assignTaskToIdleWorker( + processingJobs: Set, + globalContextPtr: number, + plugins: Plugins[], + stopAfter?: PluginState + ) { + let job: Job | undefined; + let jobInfo: JobInfo | undefined; + if (this.jobQueues.externalProgramQueue.length > 0) { + job = this.jobQueues.externalProgramQueue.shift()!; + jobInfo = { + id: job.id, + isCompileAbc: false, + }; + } else if (this.jobQueues.abcQueue.length > 0) { + job = this.jobQueues.abcQueue.shift()!; + jobInfo = { + id: job.id, + isCompileAbc: true, + }; + } + + if (!!job && !!jobInfo) { + processingJobs.add(job.id); + jobInfo.compileFileInfo = this.compileFiles.get(job.fileList[0]); + jobInfo.buildConfig = serializable(this.buildConfig); + jobInfo.plugins = plugins; + jobInfo.globalContextPtr = globalContextPtr; + jobInfo.stopAfter = stopAfter; + + this.worker.isIdle = false; + this.emitter.emit('ASSIGN_TASK', { jobInfo }); + } + } + + private checkAllTasksDone(): boolean { + return this.jobQueues.externalProgramQueue.length === 0 && this.worker.isIdle; + } + + private subscribe() { + this.emitter.on('ASSIGN_TASK', (msg) => { + const job = msg.jobInfo; + if (job.isCompileAbc) { + compileAbc(this.emitter, job, this.tracing); + } else { + compileExternalProgram(this.emitter, job, this.tracing); + } + this.emitter.emit('TASK_FINISH', { jobId: job.id }); + }); + this.emitter.on('EXIT', () => { + this.worker.isIdle = true; + console.log(`worker exiting...`); + }); + } + + async invokeWorkers(plugins: Plugins[], stopAfter?: PluginState): Promise { + const processingJobs = new Set(); + return new Promise((resolve) => { + const files: string[] = []; + Object.values(this.jobMap).forEach((job) => { + for (let i = 0; i < job.fileList.length; i++) { + files.push(job.fileList[i]); + } + }); + + const fileInfo: CompileFileInfo = this.compileFiles.values().next().value!; + const config = createGlobalConfig(fileInfo); + const globalContextPtr = createGlobalContextPtr(config, files); + + this.subscribe(); + this.emitter.on('TASK_FINISH', (msg) => { + this.worker.isIdle = true; + const jobId = msg.jobId; + processingJobs.delete(jobId); + const completedJob = this.jobMap[jobId]; + completedJob.dependants.forEach((depJobId) => { + const depJob = this.jobMap[depJobId]; + const depIndex = depJob.dependencies.indexOf(jobId); + if (depIndex !== -1) { + depJob.dependencies.splice(depIndex, 1); + if (depJob.dependencies.length === 0) { + addJobToQueues(depJob, this.jobQueues); + } + } + }); + const hasRemainingTask = + this.jobQueues.externalProgramQueue.length > 0 || this.jobQueues.abcQueue.length > 0; + if (hasRemainingTask) { + this.assignTaskToIdleWorker(processingJobs, globalContextPtr, plugins, stopAfter); + } else if (this.checkAllTasksDone()) { + console.log('All tasks completed. Exiting...'); + this.emitter.emit('EXIT'); + destroyGlobalContextPtr(globalContextPtr); + destroyGlobalConfig(config); + resolve(); + } + }); + this.emitter.on('TASK_COLLECT', (msg) => { + const jobId = msg.jobId; + const job = this.jobMap[jobId]; + const sourceType = job.isAbcJob ? 'abc' : 'external'; + const pluginStateId = msg.pluginStateId; + const pluginTestContext = msg.pluginTestContext as PluginTestContext; + const key = `${this.hashId}:${sourceType}:${pluginStateId}`; + let currentPluginTestContext; + if (PluginTestContextCache.getInstance().has(key)) { + currentPluginTestContext = { + ...PluginTestContextCache.getInstance().get(key), + ...pluginTestContext, + }; + } else { + currentPluginTestContext = pluginTestContext; + } + PluginTestContextCache.getInstance().set(key, currentPluginTestContext); + }); + + this.worker = { isIdle: true }; + this.assignTaskToIdleWorker(processingJobs, globalContextPtr, plugins, stopAfter); + }); + } + + clear(): void { + FileDependencyContextCache.getInstance().delete(this.hashId); + } +} + +export { TaskProcessor }; diff --git a/arkui-plugins/tsconfig.json b/arkui-plugins/tsconfig.json index 32677ce44..c29a9c01d 100644 --- a/arkui-plugins/tsconfig.json +++ b/arkui-plugins/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "es2018", + "target": "esnext", "lib": ["ESNext", "ESNext.WeakRef", "DOM"], - "module": "CommonJS", + "module": "esnext", "rootDir": ".", "baseUrl": ".", "outDir": "./lib", @@ -16,7 +16,8 @@ "strict": true, "skipLibCheck": true, "removeComments": false, - "isolatedModules": true + "isolatedModules": true, + "esModuleInterop": true }, "include": [ "./common/**/*.ts", diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/builder-lambda-transformer.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/builder-lambda-transformer.ts index 5e4dc8331..7a821bd74 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/builder-lambda-transformer.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/builder-lambda-transformer.ts @@ -16,15 +16,25 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; import { isBuilderLambda, isBuilderLambdaMethodDecl } from './utils'; import { factory } from './factory'; +import { ImportCollector } from '../import-collector'; +import { ProjectConfig } from '../../common/plugin-context'; export class BuilderLambdaTransformer extends AbstractVisitor { + projectConfig: ProjectConfig | undefined; + + constructor(projectConfig: ProjectConfig | undefined) { + super(); + this.projectConfig = projectConfig; + } + reset(): void { super.reset(); + ImportCollector.getInstance().reset(); } visitor(beforeChildren: arkts.AstNode): arkts.AstNode { if (arkts.isCallExpression(beforeChildren) && isBuilderLambda(beforeChildren)) { - const lambda = factory.transformBuilderLambda(beforeChildren); + const lambda = factory.transformBuilderLambda(beforeChildren, this.projectConfig); return this.visitEachChild(lambda); } if (arkts.isMethodDefinition(beforeChildren) && isBuilderLambdaMethodDecl(beforeChildren)) { @@ -32,6 +42,9 @@ export class BuilderLambdaTransformer extends AbstractVisitor { return this.visitEachChild(lambda); } const node = this.visitEachChild(beforeChildren); + if (arkts.isEtsScript(node) && ImportCollector.getInstance().importInfos.length > 0) { + ImportCollector.getInstance().insertCurrentImports(this.program); + } return node; } } diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts index e4572d2f4..ebc67b04c 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/factory.ts @@ -14,14 +14,21 @@ */ import * as arkts from '@koalaui/libarkts'; -import { BuilderLambdaNames } from '../utils'; +import { + addMemoAnnotation, + BuilderLambdaNames, + CustomComponentNames, + findCanAddMemoFromParamExpression, + findImportSource, + isCustomComponentAnnotation, +} from '../utils'; import { annotation, backingField, filterDefined, removeAnnotationByName } from '../../common/arkts-utils'; import { BuilderLambdaDeclInfo, builderLambdaFunctionName, builderLambdaMethodDeclType, - builderLambdaTypeName, callIsGoodForBuilderLambda, + collectComponentAttributeImport, findBuilderLambdaDecl, findBuilderLambdaDeclInfo, isBuilderLambda, @@ -31,19 +38,38 @@ import { BindableDecl, getDecalTypeFromValue, hasBindableProperty, - isDoubleDollarCall + isDoubleDollarCall, + builderLambdaType, } from './utils'; -import { DecoratorNames } from '../property-translators/utils'; +import { DecoratorIntrinsicNames, DecoratorNames, isDecoratorIntrinsicAnnotation } from '../property-translators/utils'; import { factory as PropertyFactory } from '../property-translators/factory'; import { ProjectConfig } from '../../common/plugin-context'; +import { ImportCollector } from '../import-collector'; export class factory { - /* - * update @ComponentBuilder decorated method. + /** + * generate `packageInfo: string` in `@ComponentBuilder` XComponent + */ + static createPackageInfoArgForXComponent(): arkts.ETSParameterExpression { + return arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + 'packageInfo', + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier('string') + ) + ) + ), + undefined + ); + } + + /** + * update `@ComponentBuilder` decorated method. */ static updateBuilderLambdaMethodDecl( node: arkts.MethodDefinition, - styleArg: arkts.ETSParameterExpression, + args: arkts.ETSParameterExpression[], newAnno: arkts.AnnotationUsage[], newName: string | undefined ): arkts.MethodDefinition { @@ -54,7 +80,7 @@ export class factory { func.body, arkts.FunctionSignature.createFunctionSignature( func.typeParams, - [styleArg, ...func.params], + [...args, ...func.params], arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), false ), @@ -82,7 +108,7 @@ export class factory { return [...call.arguments]; } const type: arkts.AstNode | undefined = arkts.isEtsParameterExpression(decl.scriptFunction.params[0]) - ? decl.scriptFunction.params[0].type + ? decl.scriptFunction.params[0].type?.clone() : undefined; if ( type && @@ -106,17 +132,17 @@ export class factory { [factory.generateValueProperty(bindableArg), factory.generateOnChangeArrowFunc(bindableArg, valueType)], false ); - return arkts.factory.createTSAsExpression( - objExp, - factory.createBindableType(valueType), - false - ); + return arkts.factory.createTSAsExpression(objExp, factory.createBindableType(valueType), false); } /* * create style instance call, e.g. `instance.margin(10)`. */ - static createStyleLambdaBody(lambdaBody: arkts.AstNode, call: arkts.CallExpression, projectConfig: ProjectConfig | undefined): arkts.CallExpression { + static createStyleLambdaBody( + lambdaBody: arkts.AstNode, + call: arkts.CallExpression, + projectConfig: ProjectConfig | undefined + ): arkts.CallExpression { const newArgs: arkts.Expression[] = factory.getTransformedStyle(call); return arkts.factory.createCallExpression( arkts.factory.createMemberExpression( @@ -160,7 +186,9 @@ export class factory { if (!lambdaBody) { return arkts.factory.createUndefinedLiteral(); } + collectComponentAttributeImport(typeNode); const safeType: arkts.TypeNode | undefined = isSafeType(typeNode) ? typeNode : undefined; + const styleLambdaParam: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier(BuilderLambdaNames.STYLE_ARROW_PARAM_NAME, safeType), undefined @@ -222,7 +250,9 @@ export class factory { undefined ); } - parameter.annotations = [annotation('memo')]; + if (findCanAddMemoFromParamExpression(parameter)) { + addMemoAnnotation(parameter); + } return parameter; } @@ -230,15 +260,18 @@ export class factory { * If a builder lambda's argument is an arrow function, * then transform any builder lambda in the function body. */ - static processArgArrowFunction(arg: arkts.ArrowFunctionExpression, projectConfig: ProjectConfig | undefined): arkts.ArrowFunctionExpression { + static processArgArrowFunction( + arg: arkts.ArrowFunctionExpression, + projectConfig: ProjectConfig | undefined + ): arkts.ArrowFunctionExpression { const func: arkts.ScriptFunction = arg.scriptFunction; const updateFunc = arkts.factory.updateScriptFunction( func, !!func.body && arkts.isBlockStatement(func.body) ? arkts.factory.updateBlock( - func.body, - func.body.statements.map((st) => this.updateContentBodyInBuilderLambda(st, projectConfig)) - ) + func.body, + func.body.statements.map((st) => this.updateContentBodyInBuilderLambda(st, projectConfig)) + ) : undefined, arkts.FunctionSignature.createFunctionSignature( func.typeParams, @@ -262,16 +295,10 @@ export class factory { } else if (arkts.isObjectExpression(arg)) { expr = arg; } - if (!expr) { return arg; } - - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(typeName!); - const properties = expr.properties as arkts.Property[]; - properties.forEach((prop, index) => { - this.updateParameterPassingInLinkedProperties(prop, index, currentStructInfo, properties); - }); + const properties = (expr.properties as arkts.Property[]).map((p) => factory.updatePropertiesInOptions(p)); const updatedExpr: arkts.ObjectExpression = arkts.ObjectExpression.updateObjectExpression( expr, arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, @@ -284,49 +311,32 @@ export class factory { return updatedExpr as T; } - /** - * update any `@Link` parameter passing to the custom-component child. - */ - static updateParameterPassingInLinkedProperties( - prop: arkts.Property, - index: number, - currentStructInfo: arkts.StructInfo, - properties: arkts.Property[] - ): void { - const decl = prop.key ? arkts.getDecl(prop.key) : undefined; - if (decl && arkts.isMethodDefinition(decl)) { - const type: arkts.TypeNode | undefined = decl.scriptFunction.returnTypeAnnotation; - if ( - type && - hasBindableProperty(type, BindableDecl.BINDABLE) && - arkts.isProperty(prop) && - prop.value && - isDoubleDollarCall(prop.value) - ) { - properties[index] = factory.updateBindableProperty(prop); - } + static updatePropertiesInOptions(prop: arkts.Property): arkts.Property { + let decl: arkts.AstNode | undefined; + if (!prop.key || !prop.value || !(decl = arkts.getDecl(prop.key)) || !arkts.isMethodDefinition(decl)) { + return prop; } - if ( - !!prop.key && - !!prop.value && + const returnType: arkts.TypeNode | undefined = decl.scriptFunction.returnTypeAnnotation; + const isBindable: boolean = !!returnType && hasBindableProperty(returnType, BindableDecl.BINDABLE); + const isLinkIntrinsic: boolean = decl.scriptFunction.annotations.some((anno) => + isDecoratorIntrinsicAnnotation(anno, DecoratorIntrinsicNames.LINK) + ); + if (isBindable && isDoubleDollarCall(prop.value)) { + return factory.updateBindableProperty(prop); + } else if ( + isLinkIntrinsic && arkts.isIdentifier(prop.key) && arkts.isMemberExpression(prop.value) && arkts.isThisExpression(prop.value.object) && arkts.isIdentifier(prop.value.property) ) { - const structVariableMetadata = currentStructInfo.metadata[prop.key.name]; - if ( - structVariableMetadata && - structVariableMetadata.properties.length && - structVariableMetadata.properties.includes(DecoratorNames.LINK) - ) { - properties[index] = arkts.Property.updateProperty( - prop, - arkts.factory.createIdentifier(backingField(prop.key.name)), - this.updateBackingMember(prop.value, prop.value.property.name) - ); - } + return arkts.Property.updateProperty( + prop, + arkts.factory.createIdentifier(backingField(prop.key.name)), + factory.updateBackingMember(prop.value, prop.value.property.name) + ); } + return prop; } /** @@ -337,9 +347,10 @@ export class factory { arg: arkts.Expression | undefined, projectConfig: ProjectConfig | undefined, typeName?: string, - ): arkts.AstNode { + fallback?: arkts.AstNode + ): arkts.AstNode | undefined { if (!arg) { - return arkts.factory.createUndefinedLiteral(); + return fallback; } if (arkts.isArrowFunctionExpression(arg)) { return this.processArgArrowFunction(arg, projectConfig); @@ -360,33 +371,56 @@ export class factory { declInfo: BuilderLambdaDeclInfo, projectConfig: ProjectConfig | undefined ): (arkts.AstNode | undefined)[] { - const { params, returnType } = declInfo; - const typeName: string | undefined = builderLambdaTypeName(leaf); + const { isFunctionCall, params, returnType } = declInfo; + const type: arkts.Identifier | undefined = builderLambdaType(leaf); + let isReusable: boolean | undefined; + let reuseId: arkts.StringLiteral | undefined; + if (!isFunctionCall && !!type) { + const customComponentDecl = arkts.getDecl(type); + isReusable = + !!customComponentDecl && + arkts.isClassDefinition(customComponentDecl) && + customComponentDecl.annotations.some((anno) => + isCustomComponentAnnotation(anno, CustomComponentNames.RESUABLE_ANNOTATION) + ); + reuseId = isReusable ? arkts.factory.createStringLiteral(type.name) : undefined; + } const args: (arkts.AstNode | undefined)[] = [this.createStyleArgInBuilderLambda(lambdaBody, returnType)]; let index = 0; while (index < params.length) { - args.push(this.createOrUpdateArgInBuilderLambda(leaf.arguments.at(index), projectConfig, typeName)); - index++; - } - const isReusable: boolean = typeName - ? arkts.GlobalInfo.getInfoInstance().getStructInfo(typeName).isReusable : false; - if (isReusable) { - args.splice(-1, 1, arkts.factory.createStringLiteral(typeName!)); - } - else if (typeName === 'XComponent') { - let packageInfo: string = ''; - if (projectConfig?.bundleName && projectConfig?.moduleName) { - packageInfo = projectConfig?.bundleName + '/' + projectConfig?.moduleName; + if (isReusable && params.length > 1 && index === params.length - 2) { + args.push( + this.createOrUpdateArgInBuilderLambda(leaf.arguments.at(index), projectConfig, type?.name, reuseId) + ); + } else if (type?.name === 'XComponent' && index === params.length - 1) { + let packageInfo: string = ''; + if (projectConfig?.bundleName && projectConfig?.moduleName) { + packageInfo = projectConfig?.bundleName + '/' + projectConfig?.moduleName; + } + const packageInfoNode = arkts.factory.createStringLiteral(packageInfo); + args.push( + this.createOrUpdateArgInBuilderLambda( + leaf.arguments.at(index), + projectConfig, + type?.name, + packageInfoNode + ) + ); + } else { + args.push(this.createOrUpdateArgInBuilderLambda(leaf.arguments.at(index), projectConfig, type?.name)); } - args.splice(args.length - 1, 0, arkts.factory.createStringLiteral(packageInfo)); + index++; } - return args; + return filterDefined(args); } /** * update if-else in trailing lambda contents in a builder lambda call. */ - static updateIfElseContentBodyInBuilderLambda(statement: arkts.AstNode, projectConfig: ProjectConfig | undefined): arkts.AstNode { + static updateIfElseContentBodyInBuilderLambda( + statement: arkts.AstNode, + projectConfig: ProjectConfig | undefined + ): arkts.AstNode { if (arkts.isIfStatement(statement)) { const alternate = !!statement.alternate ? this.updateIfElseContentBodyInBuilderLambda(statement.alternate, projectConfig) @@ -406,7 +440,10 @@ export class factory { /** * update trailing lambda contents in a builder lambda call. */ - static updateContentBodyInBuilderLambda(statement: arkts.Statement, projectConfig: ProjectConfig | undefined): arkts.Statement { + static updateContentBodyInBuilderLambda( + statement: arkts.Statement, + projectConfig: ProjectConfig | undefined + ): arkts.Statement { if ( arkts.isExpressionStatement(statement) && arkts.isCallExpression(statement.expression) && @@ -454,18 +491,22 @@ export class factory { /** * transform `@ComponentBuilder` in declared methods. */ - static transformBuilderLambdaMethodDecl(node: arkts.MethodDefinition): arkts.MethodDefinition { + static transformBuilderLambdaMethodDecl(node: arkts.MethodDefinition, externalSourceName?: string): arkts.MethodDefinition { const func: arkts.ScriptFunction = node.scriptFunction; const isFunctionCall: boolean = isBuilderLambdaFunctionCall(node); const typeNode: arkts.TypeNode | undefined = builderLambdaMethodDeclType(node); - const styleArg: arkts.ETSParameterExpression = this.createStyleArgInBuilderLambdaDecl(typeNode, isFunctionCall); + const newArgs: arkts.ETSParameterExpression[] = []; + newArgs.push(this.createStyleArgInBuilderLambdaDecl(typeNode, isFunctionCall)); + if (externalSourceName === 'arkui.component.xcomponent' && node.name.name === 'XComponent') { + newArgs.push(this.createPackageInfoArgForXComponent()); + } const newOverloads: arkts.MethodDefinition[] = node.overloads.map((method) => factory.transformBuilderLambdaMethodDecl(method) ); return this.updateBuilderLambdaMethodDecl( node, - styleArg, + newArgs, removeAnnotationByName(func.annotations, BuilderLambdaNames.ANNOTATION_NAME), replaceBuilderLambdaDeclMethodName(node.name.name) ).setOverloads(newOverloads); @@ -489,7 +530,7 @@ export class factory { const aniStop: arkts.CallExpression = arkts.factory.createCallExpression( arkts.factory.createIdentifier(BuilderLambdaNames.ANIMATION_STOP), undefined, - instanceCalls[curIdx].arguments.map((arg)=>arg.clone()) + instanceCalls[curIdx].arguments.map((arg) => arg.clone()) ); instanceCalls.splice(lastAniIdx, 0, aniStart); instanceCalls[curIdx + 1] = aniStop; @@ -538,7 +579,12 @@ export class factory { }); } - const args: (arkts.AstNode | undefined)[] = this.generateArgsInBuilderLambda(leaf, lambdaBody!, declInfo, projectConfig); + const args: (arkts.AstNode | undefined)[] = this.generateArgsInBuilderLambda( + leaf, + lambdaBody!, + declInfo, + projectConfig + ); return arkts.factory.updateCallExpression(node, replace, leaf.typeArguments, filterDefined(args)); } @@ -615,9 +661,13 @@ export class factory { * generate `Bindable`. */ static createBindableType(valueType: arkts.TypeNode): arkts.ETSTypeReference { + const transformedKey = BindableDecl.BINDABLE; + const source = findImportSource(transformedKey); + ImportCollector.getInstance().collectSource(transformedKey, source); + ImportCollector.getInstance().collectImport(transformedKey); return arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(BindableDecl.BINDABLE), + arkts.factory.createIdentifier(transformedKey), arkts.factory.createTSTypeParameterInstantiation([valueType.clone()]) ) ); diff --git a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts index c220640f5..51814013a 100644 --- a/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts +++ b/arkui-plugins/ui-plugins/builder-lambda-translators/utils.ts @@ -16,6 +16,9 @@ import * as arkts from '@koalaui/libarkts'; import { isAnnotation } from '../../common/arkts-utils'; import { BuilderLambdaNames, Dollars } from '../utils'; +import { ImportCollector } from '../import-collector'; +import { DeclarationCollector } from '../../common/declaration-collector'; +import { ARKUI_COMPONENT_IMPORT_NAME } from '../../common/predefines'; export type BuilderLambdaDeclInfo = { isFunctionCall: boolean; // isFunctionCall means it is from $_instantiate. @@ -49,12 +52,7 @@ export function builderLambdaArgumentName(annotation: arkts.AnnotationUsage): st return property.value.str; } -/** - * Determine whether it is a custom component. - * - * @param node class declaration node - */ -export function isBuilderLambda(node: arkts.AstNode, isExternal?: boolean): boolean { +export function isBuilderLambda(node: arkts.AstNode): boolean { const builderLambdaCall: arkts.AstNode | undefined = getDeclForBuilderLambda(node); return !!builderLambdaCall; } @@ -71,15 +69,12 @@ export function replaceBuilderLambdaDeclMethodName(name: string | undefined): st return undefined; } -export function isBuilderLambdaMethodDecl(node: arkts.AstNode, isExternal?: boolean): boolean { +export function isBuilderLambdaMethodDecl(node: arkts.AstNode): boolean { const builderLambdaMethodDecl: arkts.AstNode | undefined = getDeclForBuilderLambdaMethodDecl(node); return !!builderLambdaMethodDecl; } -export function getDeclForBuilderLambdaMethodDecl( - node: arkts.AstNode, - isExternal?: boolean -): arkts.AstNode | undefined { +export function getDeclForBuilderLambdaMethodDecl(node: arkts.AstNode): arkts.AstNode | undefined { if (!node || !arkts.isMethodDefinition(node)) { return undefined; } @@ -94,7 +89,7 @@ export function getDeclForBuilderLambdaMethodDecl( return undefined; } -export function getDeclForBuilderLambda(node: arkts.AstNode, isExternal?: boolean): arkts.AstNode | undefined { +export function getDeclForBuilderLambda(node: arkts.AstNode): arkts.AstNode | undefined { if (!node || !arkts.isCallExpression(node)) { return undefined; } @@ -211,6 +206,7 @@ export function findBuilderLambdaDecl(node: arkts.CallExpression | arkts.Identif if (!decl) { return undefined; } + DeclarationCollector.getInstance().collect(decl); return decl; } @@ -281,17 +277,17 @@ export function builderLambdaMethodDeclType(method: arkts.MethodDefinition): ark return method.scriptFunction.returnTypeAnnotation; } -export function builderLambdaTypeName(leaf: arkts.CallExpression): string | undefined { +export function builderLambdaType(leaf: arkts.CallExpression): arkts.Identifier | undefined { if (!callIsGoodForBuilderLambda(leaf)) { return undefined; } const node = leaf.expression; - let name: string | undefined; + let name: arkts.Identifier | undefined; if (arkts.isIdentifier(node)) { - name = node.name; + name = node; } if (arkts.isMemberExpression(node) && arkts.isIdentifier(node.object)) { - name = node.object.name; + name = node.object; } return name; } @@ -344,7 +340,7 @@ export function hasBindableProperty(type: arkts.AstNode, bindableDecl: BindableD * * @param value expression node */ -export function isDoubleDollarCall(value: arkts.Expression): boolean { +export function isDoubleDollarCall(value: arkts.Expression): value is arkts.CallExpression { if ( arkts.isCallExpression(value) && value.expression && @@ -408,3 +404,24 @@ export function getElementTypeFromArray(arrayType: arkts.TypeNode): arkts.TypeNo } return undefined; } + +export function collectComponentAttributeImport(type: arkts.TypeNode | undefined): void { + if ( + !type || + !arkts.isETSTypeReference(type) || + !type.part || + !type.part.name || + !arkts.isIdentifier(type.part.name) + ) { + return; + } + + const regex: RegExp = /(?\w+Attribute)(?:<.*>)?$/; + const name: string = type.part.name.name; + const match: RegExpExecArray | null = regex.exec(name); + const attributeName: string | undefined = match?.groups?.source; + if (!!attributeName) { + ImportCollector.getInstance().collectSource(attributeName, ARKUI_COMPONENT_IMPORT_NAME); + ImportCollector.getInstance().collectImport(attributeName); + } +} diff --git a/arkui-plugins/ui-plugins/checked-transformer.ts b/arkui-plugins/ui-plugins/checked-transformer.ts index 9ab64ff2b..8539b023f 100644 --- a/arkui-plugins/ui-plugins/checked-transformer.ts +++ b/arkui-plugins/ui-plugins/checked-transformer.ts @@ -17,67 +17,66 @@ import * as arkts from '@koalaui/libarkts'; import { ProjectConfig } from '../common/plugin-context'; import { factory as structFactory } from './struct-translators/factory'; import { factory as builderLambdaFactory } from './builder-lambda-translators/factory'; -import { factory as uiFactory } from './ui-factory'; import { factory as entryFactory } from './entry-translators/factory'; import { AbstractVisitor } from '../common/abstract-visitor'; -import { annotation, collect, filterDefined } from '../common/arkts-utils'; import { - CustomComponentNames, - getCustomComponentOptionsName, - getTypeNameFromTypeParameter, - getTypeParamsFromClassDecl, - getGettersFromClassDecl, addMemoAnnotation, + collectCustomComponentScopeInfo, + CustomComponentNames, + isCustomComponentClass, } from './utils'; -import { hasDecorator, DecoratorNames } from './property-translators/utils'; import { - isCustomComponentClass, - isKnownMethodDefinition, - isEtsGlobalClass, - isReourceNode, - ScopeInfoCollection, CustomComponentScopeInfo, - isMemoCall, + ScopeInfoCollection, findCanAddMemoFromArrowFunction, + isReourceNode, } from './struct-translators/utils'; import { isBuilderLambda, isBuilderLambdaMethodDecl } from './builder-lambda-translators/utils'; import { isEntryWrapperClass } from './entry-translators/utils'; -import { classifyObservedTrack, classifyProperty, PropertyTranslator } from './property-translators'; -import { ObservedTrackTranslator } from './property-translators/observedTrack'; -import { nodeByType } from '@koalaui/libarkts/build/src/reexport-for-generated'; +import { ImportCollector } from './import-collector'; +import { PropertyCache } from './property-translators/utils'; export class CheckedTransformer extends AbstractVisitor { - private scopeInfoCollection: ScopeInfoCollection; + private scope: ScopeInfoCollection; projectConfig: ProjectConfig | undefined; constructor(projectConfig: ProjectConfig | undefined) { super(); this.projectConfig = projectConfig; - this.scopeInfoCollection = { customComponents: [] }; + this.scope = { customComponents: [] }; } reset(): void { super.reset(); - this.scopeInfoCollection = { customComponents: [] }; + this.scope = { customComponents: [] }; + PropertyCache.getInstance().reset(); + ImportCollector.getInstance().reset(); } enter(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - this.scopeInfoCollection.customComponents.push({ name: node.definition!.ident!.name }); + if (arkts.isClassDeclaration(node) && !!node.definition && node.definition.body.length > 0) { + const customComponentInfo = collectCustomComponentScopeInfo(node); + if (!!customComponentInfo) { + this.scope.customComponents.push(customComponentInfo); + } } - if (arkts.isMethodDefinition(node) && this.scopeInfoCollection.customComponents.length > 0) { + if (arkts.isMethodDefinition(node) && this.scope.customComponents.length > 0) { const name = node.name.name; - const scopeInfo = this.scopeInfoCollection.customComponents.pop()!; + const scopeInfo = this.scope.customComponents.pop()!; scopeInfo.hasInitializeStruct ||= name === CustomComponentNames.COMPONENT_INITIALIZE_STRUCT; scopeInfo.hasUpdateStruct ||= name === CustomComponentNames.COMPONENT_UPDATE_STRUCT; scopeInfo.hasReusableRebind ||= name === CustomComponentNames.REUSABLE_COMPONENT_REBIND_STATE; - this.scopeInfoCollection.customComponents.push(scopeInfo); + this.scope.customComponents.push(scopeInfo); } } exit(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - this.scopeInfoCollection.customComponents.pop(); + if ( + arkts.isClassDeclaration(node) && + this.scope.customComponents.length > 0 && + isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) + ) { + this.scope.customComponents.pop(); } } @@ -87,386 +86,33 @@ export class CheckedTransformer extends AbstractVisitor { const lambda = builderLambdaFactory.transformBuilderLambda(beforeChildren, this.projectConfig); return this.visitEachChild(lambda); } else if (arkts.isMethodDefinition(beforeChildren) && isBuilderLambdaMethodDecl(beforeChildren)) { - const lambda = builderLambdaFactory.transformBuilderLambdaMethodDecl(beforeChildren); + const lambda = builderLambdaFactory.transformBuilderLambdaMethodDecl(beforeChildren, this.externalSourceName); return this.visitEachChild(lambda); } const node = this.visitEachChild(beforeChildren); - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - let scope: CustomComponentScopeInfo | undefined; - const scopeInfos: CustomComponentScopeInfo[] = this.scopeInfoCollection.customComponents; - if (scopeInfos.length > 0) { - scope = scopeInfos[scopeInfos.length - 1]; - } - const newClass: arkts.ClassDeclaration = tranformClassMembers( - node, - arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE), - scope - ); + if ( + arkts.isClassDeclaration(node) && + this.scope.customComponents.length > 0 && + isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) + ) { + const scope: CustomComponentScopeInfo = this.scope.customComponents[this.scope.customComponents.length - 1]; + const newClass: arkts.ClassDeclaration = structFactory.tranformClassMembers(node, scope); this.exit(beforeChildren); return newClass; } else if (isEntryWrapperClass(node)) { entryFactory.addMemoToEntryWrapperClassMethods(node); return node; - } else if (arkts.isClassDeclaration(node) && isEtsGlobalClass(node)) { - return transformEtsGlobalClassMembers(node); + } else if (arkts.isClassDeclaration(node)) { + return structFactory.transformNormalClass(node); } else if (arkts.isCallExpression(node) && isReourceNode(node)) { - return transformResource(node, this.projectConfig); + return structFactory.transformResource(node, this.projectConfig); + } else if (arkts.isTSInterfaceDeclaration(node)) { + return structFactory.tranformInterfaceMembers(node, this.externalSourceName); } else if (findCanAddMemoFromArrowFunction(node)) { return addMemoAnnotation(node); - } else if (arkts.isClassDeclaration(node)) { - return transformObservedTracked(node); - } else if (this.externalSourceName) { - return structFactory.transformExternalSource(this.externalSourceName, node); + } else if (arkts.isEtsScript(node) && ImportCollector.getInstance().importInfos.length > 0) { + ImportCollector.getInstance().insertCurrentImports(this.program); } return node; } } - -export type ClassScopeInfo = { - isObserved: boolean; - classHasTrack: boolean; - getters: arkts.MethodDefinition[] -}; - -function transformObservedTracked(node: arkts.ClassDeclaration): arkts.ClassDeclaration { - if (!node.definition) { - return node; - } - const isObserved: boolean = hasDecorator(node.definition, DecoratorNames.OBSERVED); - const classHasTrack: boolean = node.definition.body.some( - (member) => arkts.isClassProperty(member) && hasDecorator(member, DecoratorNames.TRACK) - ); - if (!isObserved && !classHasTrack) { - return node; - } - - const updateClassDef: arkts.ClassDefinition = arkts.factory.updateClassDefinition( - node.definition, - node.definition.ident, - node.definition.typeParams, - node.definition.superTypeParams, - [ - ...node.definition.implements, - arkts.TSClassImplements.createTSClassImplements( - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('IObservedObject')) - ) - ), - ], - undefined, - node.definition.super, - observedTrackPropertyMembers(classHasTrack, node.definition, isObserved), - node.definition.modifiers, - arkts.classDefinitionFlags(node.definition) - ); - return arkts.factory.updateClassDeclaration(node, updateClassDef); -} - -function observedTrackPropertyMembers( - classHasTrack: boolean, - definition: arkts.ClassDefinition, - isObserved: boolean -): arkts.AstNode[] { - const watchMembers: arkts.AstNode[] = createWatchMembers(); - const permissibleAddRefDepth: arkts.ClassProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier('_permissibleAddRefDepth'), - arkts.factory.createNumericLiteral(0), - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('int32')) - ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - false - ); - - const meta: arkts.ClassProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier('__meta'), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('MutableStateMeta')) - ), - [arkts.factory.createStringLiteral('@Observe properties (no @Track)')] - ), - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('MutableStateMeta')) - ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); - - const getters: arkts.MethodDefinition[] = getGettersFromClassDecl(definition); - - const classScopeInfo: ClassScopeInfo = { - isObserved: isObserved, - classHasTrack: classHasTrack, - getters: getters, - }; - - const propertyTranslators: ObservedTrackTranslator[] = filterDefined( - definition.body.map((it) => classifyObservedTrack(it, classScopeInfo)) - ); - - const propertyMembers = propertyTranslators.map((translator) => translator.translateMember()); - - const nonClassPropertyOrGetter: arkts.AstNode[] = definition.body.filter( - (member) => - !arkts.isClassProperty(member) && - !( - arkts.isMethodDefinition(member) && - arkts.hasModifierFlag(member, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_GETTER) - ) - ); - - return [ - ...watchMembers, - ...(classHasTrack ? [permissibleAddRefDepth] : [permissibleAddRefDepth, meta]), - ...collect(...propertyMembers), - ...nonClassPropertyOrGetter, - ...classScopeInfo.getters, - ]; -} - -function createWatchMethod( - methodName: string, - returnType: arkts.Es2pandaPrimitiveType, - paramName: string, - paramType: string, - isReturnStatement: boolean -): arkts.MethodDefinition { - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, - arkts.factory.createIdentifier(methodName), - arkts.factory.createFunctionExpression( - arkts.factory.createScriptFunction( - arkts.factory.createBlock([ - isReturnStatement - ? arkts.factory.createReturnStatement( - arkts.factory.createCallExpression(thisSubscribedWatchesMember(methodName), undefined, [ - arkts.factory.createIdentifier(paramName), - ]) - ) - : arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(thisSubscribedWatchesMember(methodName), undefined, [ - arkts.factory.createIdentifier(paramName), - ]) - ), - ]), - arkts.factory.createFunctionSignature( - undefined, - [ - arkts.factory.createParameterDeclaration( - arkts.factory.createIdentifier( - paramName, - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(paramType)) - ) - ), - undefined - ), - ], - arkts.factory.createPrimitiveType(returnType), - false - ), - arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC - ) - ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, - false - ); -} - -function createWatchMembers(): arkts.AstNode[] { - const subscribedWatches: arkts.ClassProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier('subscribedWatches'), - arkts.factory.createETSNewClassInstanceExpression( - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('SubscribedWatches')) - ), - [] - ), - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('SubscribedWatches')) - ), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, - false - ); - - const addWatchSubscriber = createWatchMethod( - 'addWatchSubscriber', - arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID, - 'watchId', - 'WatchIdType', - false - ); - - const removeWatchSubscriber = createWatchMethod( - 'removeWatchSubscriber', - arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_BOOLEAN, - 'watchId', - 'WatchIdType', - true - ); - - const executeOnSubscribingWatches = createWatchMethod( - 'executeOnSubscribingWatches', - arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID, - 'propertyName', - 'string', - false - ); - - return [subscribedWatches, addWatchSubscriber, removeWatchSubscriber, executeOnSubscribingWatches]; -} - -function thisSubscribedWatchesMember(member: string): arkts.MemberExpression { - return arkts.factory.createMemberExpression( - arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier('subscribedWatches'), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ), - arkts.factory.createIdentifier(member), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); -} - -/** - * @deprecated - */ -function tranformClassMembers( - node: arkts.ClassDeclaration, - isDecl?: boolean, - scope?: CustomComponentScopeInfo -): arkts.ClassDeclaration { - if (!node.definition) { - return node; - } - - let classTypeName: string | undefined; - let classOptionsName: string | undefined; - if (isDecl) { - const [classType, classOptions] = getTypeParamsFromClassDecl(node); - classTypeName = getTypeNameFromTypeParameter(classType); - classOptionsName = getTypeNameFromTypeParameter(classOptions); - } - const definition: arkts.ClassDefinition = node.definition; - const className: string | undefined = node.definition.ident?.name; - if (!className) { - throw new Error('Non Empty className expected for Component'); - } - - const propertyTranslators: PropertyTranslator[] = filterDefined( - definition.body.map((it) => classifyProperty(it, className)) - ); - const translatedMembers: arkts.AstNode[] = tranformPropertyMembers( - className, - propertyTranslators, - classOptionsName ?? getCustomComponentOptionsName(className), - isDecl, - scope - ); - const updateMembers: arkts.AstNode[] = definition.body - .filter((member) => !arkts.isClassProperty(member)) - .map((member: arkts.AstNode) => - transformOtherMembersInClass(member, classTypeName, classOptionsName, className, isDecl) - ); - - const updateClassDef: arkts.ClassDefinition = structFactory.updateCustomComponentClass(definition, [ - ...translatedMembers, - ...updateMembers, - ]); - return arkts.factory.updateClassDeclaration(node, updateClassDef); -} - -/** - * @deprecated - */ -function transformOtherMembersInClass( - member: arkts.AstNode, - classTypeName: string | undefined, - classOptionsName: string | undefined, - className: string, - isDecl?: boolean -): arkts.AstNode { - if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.BUILDER)) { - member.scriptFunction.setAnnotations([annotation('memo')]); - return member; - } - if ( - arkts.isMethodDefinition(member) && - isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI) && - !isDecl - ) { - return uiFactory.createConstructorMethod(member); - } - if (arkts.isMethodDefinition(member) && isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_BUILD_ORI)) { - return structFactory.transformBuildMethodWithOriginBuild( - member, - classTypeName ?? className, - classOptionsName ?? getCustomComponentOptionsName(className), - isDecl - ); - } - return member; -} - -/** - * @deprecated - */ -function tranformPropertyMembers( - className: string, - propertyTranslators: PropertyTranslator[], - optionsTypeName: string, - isDecl?: boolean, - scope?: CustomComponentScopeInfo -): arkts.AstNode[] { - const propertyMembers = propertyTranslators.map((translator) => translator.translateMember()); - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(className); - const collections = []; - if (!scope?.hasInitializeStruct) { - collections.push(structFactory.createInitializeStruct(currentStructInfo, optionsTypeName, isDecl)); - } - if (!scope?.hasUpdateStruct) { - collections.push(structFactory.createUpdateStruct(currentStructInfo, optionsTypeName, isDecl)); - } - if (currentStructInfo.isReusable) { - collections.push(structFactory.toRecord(optionsTypeName, currentStructInfo.toRecordBody)); - } - return collect(...collections, ...propertyMembers); -} - -/** - * @deprecated - */ -function transformEtsGlobalClassMembers(node: arkts.ClassDeclaration): arkts.ClassDeclaration { - if (!node.definition) { - return node; - } - node.definition.body.map((member: arkts.AstNode) => { - if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.BUILDER)) { - member.scriptFunction.setAnnotations([annotation('memo')]); - } - return member; - }); - return node; -} - -/** - * @deprecated - */ -function transformResource( - resourceNode: arkts.CallExpression, - projectConfig: ProjectConfig | undefined -): arkts.CallExpression { - const newArgs: arkts.AstNode[] = [ - arkts.factory.create1StringLiteral(projectConfig?.bundleName ? projectConfig.bundleName : ''), - arkts.factory.create1StringLiteral(projectConfig?.moduleName ? projectConfig.moduleName : ''), - ...resourceNode.arguments, - ]; - return structFactory.generateTransformedResource(resourceNode, newArgs); -} - diff --git a/arkui-plugins/ui-plugins/component-transformer.ts b/arkui-plugins/ui-plugins/component-transformer.ts index 75429bc42..82913eadc 100644 --- a/arkui-plugins/ui-plugins/component-transformer.ts +++ b/arkui-plugins/ui-plugins/component-transformer.ts @@ -21,21 +21,30 @@ import { AbstractVisitor, VisitorOptions } from '../common/abstract-visitor'; import { CustomComponentNames, getCustomComponentOptionsName, - createOptionalClassProperty, findLocalImport, + CustomComponentInfo, + collectCustomComponentScopeInfo, + isComponentStruct, } from './utils'; -import { isAnnotation, updateStructMetadata, backingField, expectName, annotation } from '../common/arkts-utils'; +import { + backingField, + expectName, + annotation, + filterDefined, + collect, +} from '../common/arkts-utils'; import { EntryWrapperNames, findEntryWithStorageInClassAnnotations } from './entry-translators/utils'; import { factory as entryFactory } from './entry-translators/factory'; import { - hasDecorator, + hasDecoratorName, DecoratorNames, - getStateManagementType, - collectPropertyDecorators + findDecoratorInfos, + isDecoratorAnnotation, + decoratorTypeMap, + DecoratorIntrinsicNames, } from './property-translators/utils'; -import { - factory -} from './ui-factory'; +import { factory } from './ui-factory'; +import { factory as propertyFactory } from './property-translators/factory'; import { StructMap } from '../common/program-visitor'; import { processStructCall } from './interop'; @@ -43,27 +52,18 @@ export interface ComponentTransformerOptions extends VisitorOptions { arkui?: string; } -type ScopeInfo = { - name: string; - isEntry?: boolean; - isComponent?: boolean; - isReusable?: boolean; -}; - -interface ComponentContext { - structMembers: Map; -} +type ScopeInfo = CustomComponentInfo; export class ComponentTransformer extends AbstractVisitor { private scopeInfos: ScopeInfo[] = []; private componentInterfaceCollection: arkts.TSInterfaceDeclaration[] = []; private entryNames: string[] = []; - private reusableNames: string[] = []; private readonly arkui?: string; - private context: ComponentContext = { structMembers: new Map() }; + private structMembersMap: Map = new Map(); private isCustomComponentImported: boolean = false; private isEntryPointImported: boolean = false; - private hasLegacy = false; + private shouldAddLinkIntrinsic: boolean = false; + private hasLegacy: boolean = false; private legacyStructMap: Map = new Map(); private legacyCallMap: Map = new Map(); @@ -78,10 +78,10 @@ export class ComponentTransformer extends AbstractVisitor { this.scopeInfos = []; this.componentInterfaceCollection = []; this.entryNames = []; - this.reusableNames = []; - this.context = { structMembers: new Map() }; + this.structMembersMap = new Map(); this.isCustomComponentImported = false; this.isEntryPointImported = false; + this.shouldAddLinkIntrinsic = false; this.hasLegacy = false; this.legacyStructMap = new Map(); this.legacyCallMap = new Map(); @@ -89,13 +89,10 @@ export class ComponentTransformer extends AbstractVisitor { enter(node: arkts.AstNode) { if (arkts.isStructDeclaration(node) && !!node.definition.ident) { - const scopeInfo: ScopeInfo = { name: node.definition.ident.name }; - node.definition.annotations.forEach((anno) => { - scopeInfo.isEntry ||= isAnnotation(anno, CustomComponentNames.ENTRY_ANNOTATION_NAME); - scopeInfo.isComponent ||= isAnnotation(anno, CustomComponentNames.COMPONENT_ANNOTATION_NAME); - scopeInfo.isReusable ||= isAnnotation(anno, CustomComponentNames.RESUABLE_ANNOTATION_NAME); - }); - this.scopeInfos.push(scopeInfo); + const info: ScopeInfo | undefined = collectCustomComponentScopeInfo(node); + if (info) { + this.scopeInfos.push(info); + } } if (arkts.isETSImportDeclaration(node) && !this.isCustomComponentImported) { this.isCustomComponentImported = !!findLocalImport( @@ -122,12 +119,6 @@ export class ComponentTransformer extends AbstractVisitor { } } - isComponentStruct(): boolean { - if (this.scopeInfos.length === 0) return false; - const scopeInfo: ScopeInfo = this.scopeInfos[this.scopeInfos.length - 1]; - return !!scopeInfo.isComponent; - } - createImportDeclaration(): void { const source: arkts.StringLiteral = arkts.factory.create1StringLiteral( this.arkui ?? CustomComponentNames.COMPONENT_DEFAULT_IMPORT @@ -150,7 +141,11 @@ export class ComponentTransformer extends AbstractVisitor { if (this.isExternal && this.componentInterfaceCollection.length === 0 && this.entryNames.length === 0) { return node; } - let updateStatements: arkts.AstNode[] = []; + const updateStatements: arkts.AstNode[] = []; + if (this.shouldAddLinkIntrinsic) { + const expr = arkts.factory.createIdentifier(DecoratorIntrinsicNames.LINK); + updateStatements.push(factory.createIntrinsicAnnotationDeclaration({ expr })); + } if (this.componentInterfaceCollection.length > 0) { if (!this.isCustomComponentImported) this.createImportDeclaration(); updateStatements.push(...this.componentInterfaceCollection); @@ -211,23 +206,22 @@ export class ComponentTransformer extends AbstractVisitor { return node; } - arkts.GlobalInfo.getInfoInstance().add(className); + arkts.insertGlobalStructInfo(className); if (arkts.isStructDeclaration(node)) { this.collectComponentMembers(node, className); } - if (scopeInfo.isReusable) { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(className); - currentStructInfo.isReusable = true; - arkts.GlobalInfo.getInfoInstance().setStructInfo(className, currentStructInfo); - } - - this.componentInterfaceCollection.push(this.generateComponentInterface(className, node.modifiers)); + const customComponentInterface = this.generateComponentInterface( + className, + node.modifiers, + Object.values(scopeInfo.annotations ?? {}).map((anno) => anno.clone()) + ); + this.componentInterfaceCollection.push(customComponentInterface); const definition: arkts.ClassDefinition = node.definition!; const newDefinitionBody: arkts.AstNode[] = []; - if (scopeInfo.isEntry) { + if (!!scopeInfo.annotations?.entry) { this.entryNames.push(className); const entryWithStorage: arkts.ClassProperty | undefined = findEntryWithStorageInClassAnnotations(definition); @@ -267,90 +261,103 @@ export class ComponentTransformer extends AbstractVisitor { staticMethodBody.push(buildCompatibleNode); } } - return arkts.factory.updateClassDefinition( - definition, - definition.ident, - undefined, - undefined, // superTypeParams doen't work - definition.implements, - undefined, - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_CLASS_NAME), - arkts.factory.createTSTypeParameterInstantiation([ - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(className)) - ), - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier( - `${CustomComponentNames.COMPONENT_INTERFACE_PREFIX}${className}` + return arkts.factory + .createClassDefinition( + definition.ident, + undefined, + undefined, // superTypeParams doen't work + definition.implements, + undefined, + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_CLASS_NAME), + arkts.factory.createTSTypeParameterInstantiation([ + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(className)) + ), + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier( + `${CustomComponentNames.COMPONENT_INTERFACE_PREFIX}${className}` + ) ) - ) - ), - ]) - ) - ), - [...newDefinitionBody, ...definition.body, ...staticMethodBody], - definition.modifiers, - arkts.classDefinitionFlags(definition) | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_FINAL - ); + ), + ]) + ) + ), + [...newDefinitionBody, ...definition.body, ...staticMethodBody], + definition.modifiers, + arkts.classDefinitionFlags(definition) | arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_FINAL + ) + .setAnnotations(definition.annotations); } - generateComponentInterface(name: string, modifiers: number): arkts.TSInterfaceDeclaration { - const interfaceNode = arkts.factory.createInterfaceDeclaration( - [], - arkts.factory.createIdentifier(getCustomComponentOptionsName(name)), - nullptr, // TODO: wtf - arkts.factory.createInterfaceBody([...(this.context.structMembers.get(name) || [])]), - false, - false - ); + generateComponentInterface( + name: string, + modifiers: number, + annotations?: readonly arkts.AnnotationUsage[] + ): arkts.TSInterfaceDeclaration { + const interfaceNode = arkts.factory + .createInterfaceDeclaration( + [], + arkts.factory.createIdentifier(getCustomComponentOptionsName(name)), + nullptr, // TODO: wtf + arkts.factory.createInterfaceBody([...(this.structMembersMap.get(name) || [])]), + false, + false + ) + .setAnnotations(annotations ?? []); interfaceNode.modifiers = modifiers; return interfaceNode; } collectComponentMembers(node: arkts.StructDeclaration, className: string): void { - const structInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(className); - if (!this.context.structMembers.has(className)) { - this.context.structMembers.set(className, []); - } - node.definition.body.map((it) => { - if (arkts.isClassProperty(it)) { - if (hasDecorator(it, DecoratorNames.PROVIDE)) { - factory.processNoAliasProvideVariable(it); - } - this.context.structMembers.get(className)!.push(...this.createInterfaceInnerMember(it, structInfo)); - } - }); - arkts.GlobalInfo.getInfoInstance().setStructInfo(className, structInfo); + const members = filterDefined( + collect( + ...node.definition.body.filter(arkts.isClassProperty).map((it) => { + // TODO: move this to afterCheck + if (hasDecoratorName(it, DecoratorNames.PROVIDE)) { + factory.processNoAliasProvideVariable(it); + } + return this.createInterfaceInnerMember(it); + }) + ) + ); + this.structMembersMap.set(className, members); } - createInterfaceInnerMember(member: arkts.ClassProperty, structInfo: arkts.StructInfo): arkts.ClassProperty[] { + createInterfaceInnerMember(member: arkts.ClassProperty): arkts.ClassProperty[] { const originalName: string = expectName(member.key); - const newName: string = backingField(originalName); - - const properties = collectPropertyDecorators(member); - const hasStateManagementType = properties.length > 0; - updateStructMetadata(structInfo, originalName, properties, member.modifiers, hasStateManagementType); - - const originMember: arkts.ClassProperty = createOptionalClassProperty( + const originMember: arkts.ClassProperty = propertyFactory.createOptionalClassProperty( originalName, member, - '', + undefined, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC ); - if (member.annotations.length > 0 && !hasDecorator(member, DecoratorNames.BUILDER_PARAM)) { - const newMember: arkts.ClassProperty = createOptionalClassProperty( - newName, - member, - getStateManagementType(member), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC - ); - return [originMember, newMember]; + const infos = findDecoratorInfos(member); + const buildParamInfo = infos.find((it) => + isDecoratorAnnotation(it.annotation, DecoratorNames.BUILDER_PARAM, true) + ); + if (!!buildParamInfo) { + originMember.setAnnotations([buildParamInfo.annotation.clone()]); + return [originMember]; } - if (hasDecorator(member, DecoratorNames.BUILDER_PARAM) && !!originMember.typeAnnotation) { - originMember.typeAnnotation.setAnnotations([annotation('memo')]); + const targetInfo = infos.find((it) => decoratorTypeMap.has(it.name)); + if (!!targetInfo) { + const newName: string = backingField(originalName); + const newMember: arkts.ClassProperty = propertyFactory + .createOptionalClassProperty( + newName, + member, + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ) + .setAnnotations([targetInfo.annotation.clone()]); + if (isDecoratorAnnotation(targetInfo.annotation, DecoratorNames.LINK, true)) { + this.shouldAddLinkIntrinsic = true; + originMember.setAnnotations([annotation(DecoratorIntrinsicNames.LINK)]); + } + return [originMember, newMember]; } return [originMember]; } @@ -362,15 +369,15 @@ export class ComponentTransformer extends AbstractVisitor { processImport(node: arkts.ETSImportDeclaration): void { const source = node.source?.str!; - const specifiers = node.specifiers; + const specifiers = node.specifiers as arkts.ImportSpecifier[]; if (this.legacyStructMap.has(source)) { const structMap = this.legacyStructMap.get(source); if (!structMap) { return; } for (const specifier of specifiers) { - const name = specifier.local.name; - if (structMap[name]) { + const name = specifier.local?.name; + if (!!name && structMap[name]) { this.legacyCallMap.set(name, structMap[name]); } } @@ -383,7 +390,11 @@ export class ComponentTransformer extends AbstractVisitor { if (arkts.isEtsScript(newNode)) { return this.processEtsScript(newNode); } - if (arkts.isStructDeclaration(newNode) && this.isComponentStruct()) { + if ( + arkts.isStructDeclaration(newNode) && + this.scopeInfos.length > 0 && + isComponentStruct(newNode, this.scopeInfos[this.scopeInfos.length - 1]) + ) { const updateNode = this.processComponent(newNode); this.exit(newNode); return updateNode; @@ -394,9 +405,9 @@ export class ComponentTransformer extends AbstractVisitor { if (arkts.isETSImportDeclaration(newNode)) { this.processImport(newNode); } - if (arkts.isCallExpression(newNode)) { - if (this.legacyCallMap.has(newNode.expression?.name)) { - const pathName = this.legacyCallMap.get(newNode.expression?.name)!; + if (arkts.isCallExpression(newNode) && arkts.isIdentifier(newNode.expression)) { + if (this.legacyCallMap.has(newNode.expression.name)) { + const pathName = this.legacyCallMap.get(newNode.expression.name)!; const args = newNode.arguments; if (args === undefined || args.length > 1 || !(args[0] instanceof arkts.ObjectExpression)) { return processStructCall(newNode, pathName); diff --git a/arkui-plugins/ui-plugins/entry-translators/factory.ts b/arkui-plugins/ui-plugins/entry-translators/factory.ts index e2d04b3d2..9be8103dd 100644 --- a/arkui-plugins/ui-plugins/entry-translators/factory.ts +++ b/arkui-plugins/ui-plugins/entry-translators/factory.ts @@ -83,11 +83,7 @@ export class factory { */ static generateEntryFunction(name: string): arkts.MethodDefinition { const exp = arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression( - arkts.factory.createIdentifier(name), - undefined, - [arkts.factory.createUndefinedLiteral()] // TODO: Add this undefined later - ) + arkts.factory.createCallExpression(arkts.factory.createIdentifier(name), undefined, []) ); const key: arkts.Identifier = arkts.factory.createIdentifier(EntryWrapperNames.ENTRY_FUNC); const block = arkts.factory.createBlock([exp]); diff --git a/arkui-plugins/ui-plugins/entry-translators/utils.ts b/arkui-plugins/ui-plugins/entry-translators/utils.ts index c3b1dfbef..0d4d9dd9b 100644 --- a/arkui-plugins/ui-plugins/entry-translators/utils.ts +++ b/arkui-plugins/ui-plugins/entry-translators/utils.ts @@ -73,7 +73,7 @@ export function isEntryWrapperClass(node: arkts.AstNode): node is arkts.ClassDec */ export function findEntryWithStorageInClassAnnotations(node: arkts.ClassDefinition): arkts.ClassProperty | undefined { const annotation = node.annotations.find((anno) => { - if (!isAnnotation(anno, CustomComponentNames.ENTRY_ANNOTATION_NAME)) return false; + if (!isAnnotation(anno, CustomComponentNames.ENTRY_ANNOTATION)) return false; const property = anno.properties?.at(0); if (!property || !arkts.isClassProperty(property)) return false; if (!property.key || !arkts.isIdentifier(property.key)) return false; diff --git a/arkui-plugins/ui-plugins/import-collector.ts b/arkui-plugins/ui-plugins/import-collector.ts new file mode 100644 index 000000000..32337ca5b --- /dev/null +++ b/arkui-plugins/ui-plugins/import-collector.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 { factory } from './ui-factory'; + +interface ImportInfo { + imported: string; + local: string; + source: string; + kind: arkts.Es2pandaImportKinds; +} + +function insertImport(importInfo: ImportInfo, program?: arkts.Program): void { + const source: arkts.StringLiteral = arkts.factory.create1StringLiteral(importInfo.source); + const imported: arkts.Identifier = arkts.factory.createIdentifier(importInfo.imported); + const local: arkts.Identifier = arkts.factory.createIdentifier(importInfo.local); + // Insert this import at the top of the script's statements. + if (!program) { + throw Error('Failed to insert import: Transformer has no program'); + } + factory.createAndInsertImportDeclaration(source, imported, local, importInfo.kind, program); +} + +export class ImportCollector { + public importInfos: ImportInfo[]; + public localMap: Map; + public sourceMap: Map; + private static instance: ImportCollector; + + /** this set is used for keeping the import sentence unique */ + private imported: Set; + + private constructor() { + this.importInfos = []; + this.imported = new Set(); + this.localMap = new Map(); + this.sourceMap = new Map(); + } + + static getInstance(): ImportCollector { + if (!this.instance) { + this.instance = new ImportCollector(); + } + return this.instance; + } + + reset(): void { + this.importInfos = []; + this.imported.clear(); + this.localMap.clear(); + this.sourceMap.clear(); + } + + collectSource(imported: string, source: string): void { + if (!this.sourceMap.has(imported)) { + this.sourceMap.set(imported, source); + } + } + + collectImport( + imported: string, + local?: string, + kind: arkts.Es2pandaImportKinds = arkts.Es2pandaImportKinds.IMPORT_KINDS_TYPE + ): void { + if (!this.sourceMap.has(imported)) { + throw new Error(`ImportCollector: import ${imported}'s source haven't been collected yet.`); + } + if (this.imported.has(imported)) return; + const source: string = this.sourceMap.get(imported)!; + const _local: string = local ?? imported; + this.importInfos.push({ + source, + imported, + local: _local, + kind, + }); + this.localMap.set(imported, _local); + this.imported.add(imported); + } + + getLocal(imported: string): string | undefined { + return this.localMap.get(imported); + } + + insertCurrentImports(program?: arkts.Program): void { + this.importInfos.forEach((importInfo) => { + insertImport(importInfo, program); + }); + } +} diff --git a/arkui-plugins/ui-plugins/index.ts b/arkui-plugins/ui-plugins/index.ts index 76e2e6883..a50014ecf 100644 --- a/arkui-plugins/ui-plugins/index.ts +++ b/arkui-plugins/ui-plugins/index.ts @@ -36,7 +36,7 @@ export function uiTransform(): Plugins { function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; console.log('[UI PLUGIN] AFTER PARSED ENTER'); - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; @@ -47,7 +47,7 @@ function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { getDumpFileName(0, 'SRC', 1, 'UI_AfterParse_Begin'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('ui-parsed'); const componentTransformer = new ComponentTransformer(); @@ -61,14 +61,14 @@ function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { }); program = programVisitor.programVisitor(program); script = program.astNode; - arkts.Performance.getInstance().stopEvent('ui-parsed', true); + arkts.Performance.getInstance().stopEvent('ui-parsed', false); debugLog('[AFTER PARSED SCRIPT] script: ', script.dumpSrc()); debugDump( script.dumpSrc(), getDumpFileName(0, 'SRC', 2, 'UI_AfterParse_End'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); this.setArkTSAst(script); console.log('[UI PLUGIN] AFTER PARSED EXIT'); @@ -81,7 +81,7 @@ function parsedTransform(this: PluginContext): arkts.EtsScript | undefined { function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { let script: arkts.EtsScript | undefined; console.log('[UI PLUGIN] AFTER CHECKED ENTER'); - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; if (!!contextPtr) { let program = arkts.getOrUpdateGlobalContext(contextPtr).program; script = program.astNode; @@ -92,7 +92,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { getDumpFileName(0, 'SRC', 3, 'UI_AfterCheck_Begin'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); arkts.Performance.getInstance().createEvent('ui-checked'); const checkedTransformer = new CheckedTransformer(this.getProjectConfig()); @@ -105,20 +105,22 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { }); program = programVisitor.programVisitor(program); script = program.astNode; - arkts.Performance.getInstance().stopEvent('ui-checked', true); + arkts.Performance.getInstance().stopEvent('ui-checked', false); debugLog('[AFTER STRUCT SCRIPT] script: ', script.dumpSrc()); debugDump( script.dumpSrc(), getDumpFileName(0, 'SRC', 4, 'UI_AfterCheck_End'), true, cachePath, - program.programFileNameWithExtension + program.fileNameWithExtension ); - arkts.GlobalInfo.getInfoInstance().reset(); arkts.Performance.getInstance().createEvent('ui-recheck'); arkts.recheckSubtree(script); - arkts.Performance.getInstance().stopEvent('ui-recheck', true); - arkts.Performance.getInstance().clearAllEvents(); + arkts.Performance.getInstance().stopEvent('ui-recheck', false); + arkts.Performance.getInstance().clearAllEvents(false); + arkts.Performance.getInstance().visualizeEvents(true); + arkts.Performance.getInstance().clearHistory(); + arkts.Performance.getInstance().clearTotalDuration(); this.setArkTSAst(script); console.log('[UI PLUGIN] AFTER CHECKED EXIT'); return script; diff --git a/arkui-plugins/ui-plugins/preprocessor-transform.ts b/arkui-plugins/ui-plugins/preprocessor-transform.ts index d6f90b49c..c1e8e8e52 100644 --- a/arkui-plugins/ui-plugins/preprocessor-transform.ts +++ b/arkui-plugins/ui-plugins/preprocessor-transform.ts @@ -20,19 +20,10 @@ import { factory } from './ui-factory'; import { ARKUI_COMPONENT_IMPORT_NAME, IMPORT_SOURCE_MAP, OUTPUT_DEPENDENCY_MAP } from '../common/predefines'; import { NameCollector } from './name-collector'; -interface MemoImportCollection { - memo: boolean; - memoContextType: boolean; - memoIdType: boolean; -} - export class PreprocessorTransformer extends AbstractVisitor { private outNameArr: string[] = []; - private memoNameArr: string[] = []; private structInterfaceImport: arkts.ETSImportDeclaration[] = []; - private memoImportCollection: Partial = {}; private localComponentNames: string[] = []; - private isMemoImportOnce: boolean = false; private readonly nameCollector: NameCollector; @@ -44,17 +35,13 @@ export class PreprocessorTransformer extends AbstractVisitor { reset(): void { super.reset(); this.outNameArr = []; - this.memoNameArr = []; this.structInterfaceImport = []; - this.memoImportCollection = {}; this.localComponentNames = []; - this.isMemoImportOnce = false; } isCustomConponentDecl(node: arkts.CallExpression): boolean { - const structCollection: Set = arkts.GlobalInfo.getInfoInstance().getStructCollection(); const nodeName: string = node.expression.dumpSrc(); - if (structCollection.has(nodeName)) { + if (arkts.hasGlobalStructInfo(nodeName)) { return true; } return false; @@ -67,9 +54,7 @@ export class PreprocessorTransformer extends AbstractVisitor { transformComponentCall(node: arkts.CallExpression): arkts.TSAsExpression | arkts.CallExpression { if (node.arguments.length === 0 && node.trailingBlock) { - return arkts.factory.updateCallExpression(node, node.expression, node.typeArguments, [ - arkts.factory.createUndefinedLiteral(), - ]); + return node; } else if (arkts.isObjectExpression(node.arguments[0])) { const componentName: string = `${ CustomComponentNames.COMPONENT_INTERFACE_PREFIX @@ -114,19 +99,15 @@ export class PreprocessorTransformer extends AbstractVisitor { if (!node.source) return; const isFromCompImport: boolean = node.source.str === ARKUI_COMPONENT_IMPORT_NAME; - const structCollection: Set = arkts.GlobalInfo.getInfoInstance().getStructCollection(); node.specifiers.forEach((item: arkts.AstNode) => { if (!arkts.isImportSpecifier(item) || !item.imported?.name) return; const importName: string = item.imported.name; - this.memoImportCollection.memo ||= importName === 'memo'; - this.memoImportCollection.memoContextType ||= importName === '__memo_context_type'; - this.memoImportCollection.memoIdType ||= importName === '__memo_id_type'; if (isFromCompImport && this.nameCollector.getComponents().includes(importName)) { this.localComponentNames.push(item.local?.name ?? importName); } - if (structCollection.has(importName)) { + if (arkts.hasGlobalStructInfo(importName)) { const interfaceName: string = CustomComponentNames.COMPONENT_INTERFACE_PREFIX + importName; const newImport: arkts.ETSImportDeclaration = arkts.factory.createImportDeclaration( node.source?.clone(), @@ -182,40 +163,9 @@ export class PreprocessorTransformer extends AbstractVisitor { } } - prepareDependencyMap(node: arkts.ImportSpecifier, source: arkts.StringLiteral): void { - if (!node.imported?.name) return; - - // Handling component imports - const importName: string = node.imported.name; - const sourceName: string = source.str; - if (this.nameCollector.getComponents().includes(importName) && sourceName === ARKUI_COMPONENT_IMPORT_NAME) { - const newDependencies = [`UI${importName}Attribute`]; - this.updateOutDependencyMap(importName, newDependencies); - this.updateSourceDependencyMap(sourceName, newDependencies); - } - } - - prepareMemoImports(): void { - const newDependencies = []; - if (!this.memoImportCollection.memo) { - newDependencies.push('memo'); - } - if (!this.memoImportCollection.memoContextType) { - newDependencies.push('__memo_context_type'); - } - if (!this.memoImportCollection.memoIdType) { - newDependencies.push('__memo_id_type'); - } - if (newDependencies.length > 0) { - this.memoNameArr.push(...newDependencies); - this.isMemoImportOnce = true; - } - } - addImportWithSpecifier(node: arkts.ImportSpecifier, source: arkts.StringLiteral): void { if (!node.imported?.name) return; - this.prepareDependencyMap(node, source); const outName: string[] = this.getOutDependencyName(node.imported?.name); this.outNameArr.push(...outName); } @@ -225,7 +175,7 @@ export class PreprocessorTransformer extends AbstractVisitor { throw Error('Failed to insert import: Transformer has no program'); } - const outNames = new Set([...this.outNameArr, ...this.memoNameArr]); + const outNames = new Set([...this.outNameArr]); outNames.forEach((item: string) => { const source: string = this.getSourceDependency(item); const newImport: arkts.ETSImportDeclaration = arkts.factory.createImportDeclaration( @@ -254,13 +204,10 @@ export class PreprocessorTransformer extends AbstractVisitor { const newNode = this.visitEachChild(node); if (arkts.isCallExpression(newNode) && this.isCustomConponentDecl(newNode)) { return this.transformComponentCall(newNode); - } else if (arkts.isCallExpression(newNode) && this.isComponentFunctionCall(newNode)) { - return this.transformComponentFunctionCall(newNode); } if (arkts.isETSImportDeclaration(node)) { this.addDependencesImport(node); } else if (arkts.isEtsScript(node)) { - if (!this.isMemoImportOnce) this.prepareMemoImports(); this.updateScriptWithImport(); } return newNode; diff --git a/arkui-plugins/ui-plugins/property-translators/base.ts b/arkui-plugins/ui-plugins/property-translators/base.ts index 4be00d1c8..6601ab282 100644 --- a/arkui-plugins/ui-plugins/property-translators/base.ts +++ b/arkui-plugins/ui-plugins/property-translators/base.ts @@ -14,55 +14,31 @@ */ import * as arkts from '@koalaui/libarkts'; -import { createGetter, createSetter, getStageManagementIdent } from './utils'; -import { createOptionalClassProperty } from '../utils'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + createGetter, + createSetter, + StateManagementTypes, +} from './utils'; +import { CustomComponentInfo } from '../utils'; -export abstract class PropertyTranslator { - constructor( - protected property: arkts.ClassProperty, - protected structName: string - ) {} - - abstract translateMember(): arkts.AstNode[]; - - translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = createOptionalClassProperty( - newName, - this.property, - getStageManagementIdent(this.property), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); +export interface PropertyTranslatorOptions { + property: arkts.ClassProperty; + structInfo: CustomComponentInfo; +} - const member = arkts.factory.createTSNonNullExpression( - arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier(newName), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ) - ); - const thisValue: arkts.MemberExpression = arkts.factory.createMemberExpression( - member, - arkts.factory.createIdentifier('value'), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false - ); +export abstract class PropertyTranslator { + protected property: arkts.ClassProperty; + protected structInfo: CustomComponentInfo; - const getter: arkts.MethodDefinition = this.translateGetter( - originalName, - this.property.typeAnnotation, - thisValue - ); - const setter: arkts.MethodDefinition = this.translateSetter( - originalName, - this.property.typeAnnotation, - thisValue - ); - return [field, getter, setter]; + constructor(options: PropertyTranslatorOptions) { + this.property = options.property; + this.structInfo = options.structInfo; } + abstract translateMember(): arkts.AstNode[]; + translateGetter( originalName: string, typeAnnotation: arkts.TypeNode | undefined, @@ -77,10 +53,37 @@ export abstract class PropertyTranslator { left: arkts.MemberExpression ): arkts.MethodDefinition { const right: arkts.CallExpression = arkts.factory.createCallExpression( - arkts.factory.createIdentifier('observableProxy'), + arkts.factory.createIdentifier(StateManagementTypes.OBSERVABLE_PROXY), undefined, [arkts.factory.createIdentifier('value')] ); + collectStateManagementTypeSource(StateManagementTypes.OBSERVABLE_PROXY); + collectStateManagementTypeImport(StateManagementTypes.OBSERVABLE_PROXY); return createSetter(originalName, typeAnnotation, left, right); } } + +export type InterfacePropertyTypes = arkts.MethodDefinition | arkts.ClassProperty; + +export interface InterfacePropertyTranslatorOptions { + property: T; +} + +export abstract class InterfacePropertyTranslator + implements InterfacePropertyTranslatorOptions +{ + property: T; + + modified: boolean; + + constructor(options: InterfacePropertyTranslatorOptions) { + this.property = options.property; + this.modified = false; + } + + abstract translateProperty(): T; + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + return false; + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/builderParam.ts b/arkui-plugins/ui-plugins/property-translators/builderParam.ts index fbf600f06..62b1f532b 100644 --- a/arkui-plugins/ui-plugins/property-translators/builderParam.ts +++ b/arkui-plugins/ui-plugins/property-translators/builderParam.ts @@ -18,36 +18,40 @@ import * as arkts from '@koalaui/libarkts'; import { createGetter, createSetter, - generateThisBackingValue, generateThisBacking, - getValueInAnnotation, DecoratorNames, + hasDecorator, + removeDecorator, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; -import { createOptionalClassProperty } from '../utils'; +import { addMemoAnnotation, findCanAddMemoFromParamExpression, findCanAddMemoFromTypeAnnotation } from '../utils'; import { factory } from './factory'; 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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const mutableThis: arkts.Expression = generateThisBacking(newName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(mutableThis, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty(newName, this.property, '', - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, true); + const field: arkts.ClassProperty = factory.createOptionalClassProperty( + newName, + this.property, + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, + true + ); const thisGetValue: arkts.Expression = generateThisBacking(newName, false, true); const thisSetValue: arkts.Expression = generateThisBacking(newName, false, false); const getter: arkts.MethodDefinition = this.translateGetter( @@ -100,3 +104,68 @@ export class BuilderParamTranslator extends PropertyTranslator implements Initia ); } } + +export class BuilderParamInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateBuilderParamMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateBuilderParamPropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + return false; + } + + /** + * 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. + */ + private updateBuilderParamMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + const type: arkts.TypeNode | undefined = method.scriptFunction.returnTypeAnnotation; + if (findCanAddMemoFromTypeAnnotation(type)) { + addMemoAnnotation(type); + } + const newOverLoads = method.overloads.map((overload) => { + if (arkts.isMethodDefinition(overload)) { + return this.updateBuilderParamMethodInInterface(overload); + } + return overload; + }); + method.setOverloads(newOverLoads); + removeDecorator(method, DecoratorNames.BUILDER_PARAM); + } else if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + const param: arkts.Expression | undefined = method.scriptFunction.params.at(0); + if (findCanAddMemoFromParamExpression(param)) { + addMemoAnnotation(param); + } + removeDecorator(method, DecoratorNames.BUILDER_PARAM); + } + return 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`. + */ + 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; + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/consume.ts b/arkui-plugins/ui-plugins/property-translators/consume.ts index bbb32deb1..553f586c8 100644 --- a/arkui-plugins/ui-plugins/property-translators/consume.ts +++ b/arkui-plugins/ui-plugins/property-translators/consume.ts @@ -23,37 +23,37 @@ import { generateGetOrSetCall, getValueInAnnotation, DecoratorNames, + StateManagementTypes, + hasDecorator, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; -import { createOptionalClassProperty } from '../utils'; import { factory } from './factory'; 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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(originalName, newName); - currentStructInfo.initializeBody.push(initializeStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'ConsumeDecoratedVariable', + StateManagementTypes.CONSUME_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -101,3 +101,45 @@ export class ConsumeTranslator extends PropertyTranslator implements Initializer return arkts.factory.createExpressionStatement(assign); } } + +export class ConsumeInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.CONSUME); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/factory.ts b/arkui-plugins/ui-plugins/property-translators/factory.ts index c1f610a4b..8bbeaab0a 100644 --- a/arkui-plugins/ui-plugins/property-translators/factory.ts +++ b/arkui-plugins/ui-plugins/property-translators/factory.ts @@ -16,7 +16,17 @@ import * as arkts from '@koalaui/libarkts'; import { GenSymGenerator } from '../../common/gensym-generator'; import { factory as UIFactory } from '../ui-factory'; -import { judgeIfAddWatchFunc } from './utils'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + DecoratorNames, + decoratorTypeMap, + getValueInAnnotation, + hasDecorator, + removeDecorator, + StateManagementTypes, +} from './utils'; +import { addMemoAnnotation, findCanAddMemoFromTypeAnnotation } from '../utils'; export class factory { /** @@ -254,7 +264,7 @@ export class factory { ), arkts.factory.createBooleanLiteral(allowOverride), ]; - judgeIfAddWatchFunc(args, property); + factory.judgeIfAddWatchFunc(args, property); return arkts.factory.createCallExpression( arkts.factory.createMemberExpression( arkts.factory.createThisExpression(), @@ -280,7 +290,7 @@ export class factory { arkts.factory.create1StringLiteral(originalName), arkts.factory.create1StringLiteral(alias), ]; - judgeIfAddWatchFunc(args, property); + factory.judgeIfAddWatchFunc(args, property); return arkts.factory.createCallExpression( arkts.factory.createMemberExpression( arkts.factory.createThisExpression(), @@ -293,4 +303,312 @@ export class factory { args ); } + + 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 createOptionalClassProperty( + name: string, + property: arkts.ClassProperty, + stageManagementType: StateManagementTypes | undefined, + modifiers: arkts.Es2pandaModifierFlags, + needMemo: boolean = false + ): arkts.ClassProperty { + const newType: arkts.TypeNode | undefined = property.typeAnnotation?.clone(); + if (needMemo && findCanAddMemoFromTypeAnnotation(newType)) { + addMemoAnnotation(newType); + } + const newProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier(name), + undefined, + !!stageManagementType ? factory.createStageManagementType(stageManagementType, property) : newType, + modifiers, + false + ); + return arkts.classPropertySetOptional(newProperty, true); + } + + static createStageManagementType( + stageManagementType: StateManagementTypes, + property: arkts.ClassProperty + ): arkts.ETSTypeReference { + collectStateManagementTypeSource(stageManagementType); + collectStateManagementTypeImport(stageManagementType); + return arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(stageManagementType), + arkts.factory.createTSTypeParameterInstantiation([ + property.typeAnnotation ? property.typeAnnotation.clone() : arkts.factory.createETSUndefinedType(), + ]) + ) + ); + } + + static createWatchMembers(): arkts.AstNode[] { + const subscribedWatches: arkts.ClassProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier('subscribedWatches'), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.SUBSCRIBED_WATCHES) + ) + ), + [] + ), + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.SUBSCRIBED_WATCHES) + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, + false + ); + collectStateManagementTypeSource(StateManagementTypes.SUBSCRIBED_WATCHES); + collectStateManagementTypeImport(StateManagementTypes.SUBSCRIBED_WATCHES); + + const addWatchSubscriber = factory.createWatchMethod( + 'addWatchSubscriber', + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID, + 'watchId', + StateManagementTypes.WATCH_ID_TYPE, + false + ); + const removeWatchSubscriber = factory.createWatchMethod( + 'removeWatchSubscriber', + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_BOOLEAN, + 'watchId', + StateManagementTypes.WATCH_ID_TYPE, + true + ); + collectStateManagementTypeSource(StateManagementTypes.WATCH_ID_TYPE); + collectStateManagementTypeImport(StateManagementTypes.WATCH_ID_TYPE); + + const executeOnSubscribingWatches = factory.createWatchMethod( + 'executeOnSubscribingWatches', + arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID, + 'propertyName', + 'string', + false + ); + + return [subscribedWatches, addWatchSubscriber, removeWatchSubscriber, executeOnSubscribingWatches]; + } + + static createWatchMethod( + methodName: string, + returnType: arkts.Es2pandaPrimitiveType, + paramName: string, + paramType: string, + isReturnStatement: boolean + ): arkts.MethodDefinition { + return arkts.factory.createMethodDefinition( + arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, + arkts.factory.createIdentifier(methodName), + arkts.factory.createFunctionExpression( + arkts.factory.createScriptFunction( + arkts.factory.createBlock([ + isReturnStatement + ? arkts.factory.createReturnStatement( + arkts.factory.createCallExpression( + factory.thisSubscribedWatchesMember(methodName), + undefined, + [arkts.factory.createIdentifier(paramName)] + ) + ) + : arkts.factory.createExpressionStatement( + arkts.factory.createCallExpression( + factory.thisSubscribedWatchesMember(methodName), + undefined, + [arkts.factory.createIdentifier(paramName)] + ) + ), + ]), + arkts.factory.createFunctionSignature( + undefined, + [ + arkts.factory.createParameterDeclaration( + arkts.factory.createIdentifier( + paramName, + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(paramType)) + ) + ), + undefined + ), + ], + arkts.factory.createPrimitiveType(returnType), + false + ), + arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_METHOD, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + } + + static thisSubscribedWatchesMember(member: string): arkts.MemberExpression { + return arkts.factory.createMemberExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier('subscribedWatches'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + arkts.factory.createIdentifier(member), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ); + } + + /** + * add `@memo` to the `@Builder` methods in class. + */ + static addMemoToBuilderClassMethod(method: arkts.MethodDefinition): arkts.MethodDefinition { + if (hasDecorator(method, DecoratorNames.BUILDER)) { + removeDecorator(method, DecoratorNames.BUILDER); + addMemoAnnotation(method.scriptFunction); + } + return method; + } + + /** + * wrap interface non-undefined property type `T` to ``. + */ + static wrapInterfacePropertyType(type: arkts.TypeNode, wrapTypeName: StateManagementTypes): arkts.TypeNode { + if (arkts.isETSUnionType(type)) { + return arkts.factory.updateUnionType( + type, + type.types.map((t) => factory.wrapInterfacePropertyType(t, wrapTypeName)) + ); + } else if (!arkts.isETSUndefinedType(type)) { + return arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(wrapTypeName), + arkts.factory.createTSTypeParameterInstantiation([(type as arkts.TypeNode).clone()]) + ) + ); + } + return type; + } + + /** + * wrap interface property parameter that has non-undefined type `T` to ``. + */ + static wrapInterfacePropertyParamExpr( + param: arkts.Expression, + wrapTypeName: StateManagementTypes + ): arkts.Expression { + if (!arkts.isEtsParameterExpression(param)) { + return param; + } + if (!param.type || !arkts.isETSUnionType(param.type)) { + return param; + } + return arkts.factory.updateParameterDeclaration( + param, + arkts.factory.createIdentifier( + param.identifier.name, + factory.wrapInterfacePropertyType(param.type, wrapTypeName) + ), + param.initializer + ); + } + + static wrapStateManagementTypeToType( + type: arkts.TypeNode | undefined, + decoratorName: DecoratorNames + ): arkts.TypeNode | undefined { + let newType: arkts.TypeNode | undefined; + let wrapTypeName: StateManagementTypes | undefined; + if (!!type && !!(wrapTypeName = decoratorTypeMap.get(decoratorName))) { + collectStateManagementTypeSource(wrapTypeName); + newType = factory.wrapInterfacePropertyType(type, wrapTypeName); + collectStateManagementTypeImport(wrapTypeName); + } + return newType; + } + + static wrapStateManagementTypeToParam( + param: arkts.Expression | undefined, + decoratorName: DecoratorNames + ): arkts.Expression | undefined { + let newParam: arkts.Expression | undefined; + let wrapTypeName: StateManagementTypes | undefined; + if (!!param && !!(wrapTypeName = decoratorTypeMap.get(decoratorName))) { + collectStateManagementTypeSource(wrapTypeName); + newParam = factory.wrapInterfacePropertyParamExpr(param, wrapTypeName); + collectStateManagementTypeImport(wrapTypeName); + } + return newParam; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to ` | undefined`, where `` is getting from `DecoratorName`; + * + * @param method expecting getter with decorator annotation and a setter with decorator annotation in the overloads. + */ + static wrapStateManagementTypeToMethodInInterface( + method: arkts.MethodDefinition, + decorator: DecoratorNames + ): arkts.MethodDefinition { + if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET) { + const newType: arkts.TypeNode | undefined = factory.wrapStateManagementTypeToType( + method.scriptFunction.returnTypeAnnotation, + decorator + ); + const newOverLoads = method.overloads.map((overload) => { + if (arkts.isMethodDefinition(overload)) { + return factory.wrapStateManagementTypeToMethodInInterface(overload, decorator); + } + return overload; + }); + method.setOverloads(newOverLoads); + removeDecorator(method, decorator); + if (!!newType) { + method.scriptFunction.setReturnTypeAnnotation(newType); + } + } else if (method.kind === arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET) { + const newParam: arkts.Expression | undefined = factory.wrapStateManagementTypeToParam( + method.scriptFunction.params.at(0), + decorator + ); + removeDecorator(method, decorator); + if (!!newParam) { + return UIFactory.updateMethodDefinition(method, { function: { params: [newParam] } }); + } + } + return method; + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to ` | undefined`, where `` is getting from `DecoratorName`; + * + * @param property expecting property with decorator annotation. + */ + static wrapStateManagementTypeToPropertyInInterface( + property: arkts.ClassProperty, + decorator: DecoratorNames + ): arkts.ClassProperty { + const newType: arkts.TypeNode | undefined = factory.wrapStateManagementTypeToType( + property.typeAnnotation, + decorator + ); + removeDecorator(property, decorator); + if (!!newType) { + property.setTypeAnnotation(newType); + } + return property; + } } diff --git a/arkui-plugins/ui-plugins/property-translators/index.ts b/arkui-plugins/ui-plugins/property-translators/index.ts index 013eaa286..87c62c0ca 100644 --- a/arkui-plugins/ui-plugins/property-translators/index.ts +++ b/arkui-plugins/ui-plugins/property-translators/index.ts @@ -15,71 +15,117 @@ import * as arkts from '@koalaui/libarkts'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, PropertyTranslator } from './base'; import { DecoratorNames, hasDecorator } from './utils'; -import { StateTranslator } from './state'; -import { PropTranslator } from './prop'; -import { StorageLinkTranslator } from './storagelink'; -import { LocalStorageLinkTranslator } from './localstoragelink'; -import { LinkTranslator } from './link'; -import { ObjectLinkTranslator } from './objectlink'; -import { LocalStoragePropTranslator } from './localstorageprop'; -import { regularPropertyTranslator } from './regularProperty'; +import { StateInterfaceTranslator, StateTranslator } from './state'; +import { PropInterfaceTranslator, PropTranslator } from './prop'; +import { StorageLinkInterfaceTranslator, StorageLinkTranslator } from './storagelink'; +import { LocalStorageLinkInterfaceTranslator, LocalStorageLinkTranslator } from './localstoragelink'; +import { LinkInterfaceTranslator, LinkTranslator } from './link'; +import { ObjectLinkInterfaceTranslator, ObjectLinkTranslator } from './objectlink'; +import { LocalStoragePropInterfaceTranslator, LocalStoragePropTranslator } from './localstorageprop'; +import { RegularInterfaceTranslator, RegularPropertyTranslator } from './regularProperty'; import { staticPropertyTranslator } from './staticProperty'; -import { isStatic } from '../utils'; -import { StoragePropTranslator } from './storageProp'; -import { ConsumeTranslator } from './consume'; -import { ProvideTranslator } from './provide'; -import { BuilderParamTranslator } from './builderParam'; +import { CustomComponentInfo, isStatic } from '../utils'; +import { StoragePropInterfaceTranslator, StoragePropTranslator } from './storageProp'; +import { ConsumeInterfaceTranslator, ConsumeTranslator } from './consume'; +import { ProvideInterfaceTranslator, ProvideTranslator } from './provide'; +import { BuilderParamInterfaceTranslator, BuilderParamTranslator } from './builderParam'; import { ObservedTrackTranslator } from './observedTrack'; -import { ClassScopeInfo } from 'ui-plugins/checked-transformer'; +import { ClassScopeInfo } from './types'; -export { PropertyTranslator }; +export { PropertyTranslator, InterfacePropertyTranslator }; +export type { ClassScopeInfo }; -export function classifyProperty(member: arkts.AstNode, structName: string): PropertyTranslator | undefined { - if (!arkts.isClassProperty(member)) return undefined; - if (isStatic(member)) return new staticPropertyTranslator(member, structName); +export function classifyProperty( + property: arkts.AstNode, + structInfo: CustomComponentInfo +): PropertyTranslator | undefined { + if (!arkts.isClassProperty(property)) return undefined; + if (isStatic(property)) return new staticPropertyTranslator({ property, structInfo }); - if (hasDecorator(member, DecoratorNames.STATE)) { - return new StateTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.STATE)) { + return new StateTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.STORAGE_LINK)) { - return new StorageLinkTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.STORAGE_LINK)) { + return new StorageLinkTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.LOCAL_STORAGE_LINK)) { - return new LocalStorageLinkTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.LOCAL_STORAGE_LINK)) { + return new LocalStorageLinkTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.LINK)) { - return new LinkTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.LINK)) { + return new LinkTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.OBJECT_LINK)) { - return new ObjectLinkTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.OBJECT_LINK)) { + return new ObjectLinkTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.LOCAL_STORAGE_PROP)) { - return new LocalStoragePropTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.LOCAL_STORAGE_PROP)) { + return new LocalStoragePropTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.STORAGE_PROP)) { - return new StoragePropTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.STORAGE_PROP)) { + return new StoragePropTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.PROP)) { - return new PropTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.PROP)) { + return new PropTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.PROVIDE)) { - return new ProvideTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.PROVIDE)) { + return new ProvideTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.CONSUME)) { - return new ConsumeTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.CONSUME)) { + return new ConsumeTranslator({ property, structInfo }); } - if (hasDecorator(member, DecoratorNames.BUILDER_PARAM)) { - return new BuilderParamTranslator(member, structName); + if (hasDecorator(property, DecoratorNames.BUILDER_PARAM)) { + return new BuilderParamTranslator({ property, structInfo }); } - return new regularPropertyTranslator(member, structName); + return new RegularPropertyTranslator({ property, structInfo }); } -export function classifyObservedTrack(member: arkts.AstNode, classScopeInfo: ClassScopeInfo): ObservedTrackTranslator | undefined { +export function classifyPropertyInInterface(property: arkts.AstNode): InterfacePropertyTranslator | undefined { + if (StateInterfaceTranslator.canBeTranslated(property)) { + return new StateInterfaceTranslator({ property }); + } + if (LinkInterfaceTranslator.canBeTranslated(property)) { + return new LinkInterfaceTranslator({ property }); + } + if (PropInterfaceTranslator.canBeTranslated(property)) { + return new PropInterfaceTranslator({ property }); + } + if (ProvideInterfaceTranslator.canBeTranslated(property)) { + return new ProvideInterfaceTranslator({ property }); + } + if (ConsumeInterfaceTranslator.canBeTranslated(property)) { + return new ConsumeInterfaceTranslator({ property }); + } + if (StoragePropInterfaceTranslator.canBeTranslated(property)) { + return new StoragePropInterfaceTranslator({ property }); + } + if (StorageLinkInterfaceTranslator.canBeTranslated(property)) { + return new StorageLinkInterfaceTranslator({ property }); + } + if (BuilderParamInterfaceTranslator.canBeTranslated(property)) { + return new BuilderParamInterfaceTranslator({ property }); + } + if (LocalStoragePropInterfaceTranslator.canBeTranslated(property)) { + return new LocalStoragePropInterfaceTranslator({ property }); + } + if (LocalStorageLinkInterfaceTranslator.canBeTranslated(property)) { + return new LocalStorageLinkInterfaceTranslator({ property }); + } + if (ObjectLinkInterfaceTranslator.canBeTranslated(property)) { + return new ObjectLinkInterfaceTranslator({ property }); + } + if (RegularInterfaceTranslator.canBeTranslated(property)) { + return new RegularInterfaceTranslator({ property }); + } +} + +export function classifyObservedTrack( + member: arkts.AstNode, + classScopeInfo: ClassScopeInfo +): ObservedTrackTranslator | undefined { if (!arkts.isClassProperty(member)) { return undefined; } return new ObservedTrackTranslator(member, classScopeInfo); -} \ No newline at end of file +} diff --git a/arkui-plugins/ui-plugins/property-translators/link.ts b/arkui-plugins/ui-plugins/property-translators/link.ts index eafd90c95..f3c903310 100644 --- a/arkui-plugins/ui-plugins/property-translators/link.ts +++ b/arkui-plugins/ui-plugins/property-translators/link.ts @@ -21,32 +21,34 @@ import { createSetter2, generateThisBacking, generateGetOrSetCall, - judgeIfAddWatchFunc, + StateManagementTypes, + collectStateManagementTypeSource, + collectStateManagementTypeImport, + hasDecorator, + DecoratorNames, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; -import { createOptionalClassProperty } from '../utils'; 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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } generateInitializeStruct(newName: string, originalName: string) { @@ -61,13 +63,19 @@ export class LinkTranslator extends PropertyTranslator implements InitializerCon factory.createNonNullOrOptionalMemberExpression('initializers', newName, false, true) ), ]; - judgeIfAddWatchFunc(args, this.property); + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeSource(StateManagementTypes.LINK_DECORATED); + collectStateManagementTypeImport(StateManagementTypes.LINK_DECORATED); const consequent = arkts.BlockStatement.createBlockStatement([ arkts.factory.createExpressionStatement( arkts.factory.createAssignmentExpression( generateThisBacking(newName, false, false), arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - factory.createNewDecoratedInstantiate('LinkDecoratedVariable', this.property.typeAnnotation, args) + factory.createNewDecoratedInstantiate( + StateManagementTypes.LINK_DECORATED, + this.property.typeAnnotation, + args + ) ) ), ]); @@ -76,10 +84,10 @@ export class LinkTranslator extends PropertyTranslator implements InitializerCon } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'LinkDecoratedVariable', + StateManagementTypes.LINK_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -117,3 +125,45 @@ export class LinkTranslator extends PropertyTranslator implements InitializerCon return createSetter2(originalName, typeAnnotation, statement); } } + +export class LinkInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LINK); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts index a050e9852..aa6272427 100755 --- a/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/localstoragelink.ts @@ -16,9 +16,18 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName } from '../../common/arkts-utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; -import { DecoratorNames, generateToRecord } from './utils'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + DecoratorNames, + generateToRecord, + hasDecorator, + PropertyCache, + StateManagementTypes, +} from './utils'; +import { factory } from './factory'; function getLocalStorageLinkValueStr(node: arkts.AstNode): string | undefined { if (!arkts.isClassProperty(node) || !node.value) return undefined; @@ -54,21 +63,55 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.MUTABLE_STATE, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + + const member = arkts.factory.createTSNonNullExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier(newName), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ) + ); + const thisValue: arkts.MemberExpression = arkts.factory.createMemberExpression( + member, + arkts.factory.createIdentifier('value'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ); - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisValue + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisValue + ); + return [field, getter, setter]; } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { @@ -78,7 +121,7 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In } const call = arkts.factory.createCallExpression( - arkts.factory.createIdentifier('StorageLinkState'), + arkts.factory.createIdentifier(StateManagementTypes.STORAGE_LINK_STATE), this.property.typeAnnotation ? [this.property.typeAnnotation] : [], [ arkts.factory.createMemberExpression( @@ -92,6 +135,8 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In this.property.value ?? arkts.factory.createUndefinedLiteral(), ] ); + collectStateManagementTypeSource(StateManagementTypes.STORAGE_LINK_STATE); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_STATE); return arkts.factory.createAssignmentExpression( arkts.factory.createMemberExpression( @@ -106,3 +151,47 @@ export class LocalStorageLinkTranslator extends PropertyTranslator implements In ); } } + +export class LocalStorageLinkInterfaceTranslator< + T extends InterfacePropertyTypes +> extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL_STORAGE_LINK); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts b/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts index d20d982cd..ff734e899 100644 --- a/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts +++ b/arkui-plugins/ui-plugins/property-translators/localstorageprop.ts @@ -15,10 +15,19 @@ import * as arkts from '@koalaui/libarkts'; -import { DecoratorNames, generateToRecord } from './utils'; -import { PropertyTranslator } from './base'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + DecoratorNames, + generateToRecord, + hasDecorator, + PropertyCache, + StateManagementTypes, +} from './utils'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; +import { factory } from './factory'; function getLocalStorageporpValueStr(node: arkts.AstNode): string | undefined { if (!arkts.isClassProperty(node) || !node.value) return undefined; @@ -54,23 +63,57 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); const updateStruct: arkts.AstNode = this.generateUpdateStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - currentStructInfo.updateBody.push(updateStruct); - - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } + } + + translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const field = factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.SYNCED_PROPERTY, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + + const member = arkts.factory.createTSNonNullExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier(newName), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ) + ); + const thisValue: arkts.MemberExpression = arkts.factory.createMemberExpression( + member, + arkts.factory.createIdentifier('value'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ); - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); + const getter: arkts.MethodDefinition = this.translateGetter( + originalName, + this.property.typeAnnotation, + thisValue + ); + const setter: arkts.MethodDefinition = this.translateSetter( + originalName, + this.property.typeAnnotation, + thisValue + ); + return [field, getter, setter]; } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { @@ -86,7 +129,7 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In false ); const binaryItem = arkts.factory.createCallExpression( - arkts.factory.createIdentifier('StorageLinkState'), + arkts.factory.createIdentifier(StateManagementTypes.STORAGE_LINK_STATE), this.property.typeAnnotation ? [this.property.typeAnnotation] : [], [ insideMember, @@ -94,8 +137,10 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In this.property.value ?? arkts.factory.createUndefinedLiteral(), ] ); + collectStateManagementTypeSource(StateManagementTypes.STORAGE_LINK_STATE); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_STATE); const call = arkts.factory.createCallExpression( - arkts.factory.createIdentifier('propState'), + arkts.factory.createIdentifier(StateManagementTypes.PROP_STATE), this.property.typeAnnotation ? [this.property.typeAnnotation] : [], [ arkts.factory.createMemberExpression( @@ -107,6 +152,8 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In ), ] ); + collectStateManagementTypeSource(StateManagementTypes.PROP_STATE); + collectStateManagementTypeImport(StateManagementTypes.PROP_STATE); return arkts.factory.createAssignmentExpression( arkts.factory.createMemberExpression( arkts.factory.createThisExpression(), @@ -128,7 +175,7 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In const StorageLinkStateValue = arkts.factory.createMemberExpression( arkts.factory.createCallExpression( - arkts.factory.createIdentifier('StorageLinkState'), + arkts.factory.createIdentifier(StateManagementTypes.STORAGE_LINK_STATE), this.property.typeAnnotation ? [this.property.typeAnnotation] : [], [ arkts.factory.createMemberExpression( @@ -147,6 +194,8 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In false, false ); + collectStateManagementTypeSource(StateManagementTypes.STORAGE_LINK_STATE); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_STATE); const test = arkts.factory.createMemberExpression( arkts.factory.createThisExpression(), @@ -175,3 +224,47 @@ export class LocalStoragePropTranslator extends PropertyTranslator implements In return arkts.factory.createExpressionStatement(arkts.factory.createIfStatement(test, consequent)); } } + +export class LocalStoragePropInterfaceTranslator< + T extends InterfacePropertyTypes +> extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `SyncedProperty | undefined`. + * + * @param method expecting getter with `@LocalStorageProp` and a setter with `@LocalStorageProp` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.LOCAL_STORAGE_PROP); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `SyncedProperty | undefined`. + * + * @param property expecting property with `@LocalStorageProp`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.LOCAL_STORAGE_PROP); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/objectlink.ts b/arkui-plugins/ui-plugins/property-translators/objectlink.ts index 8da1283a2..ec201c5a1 100644 --- a/arkui-plugins/ui-plugins/property-translators/objectlink.ts +++ b/arkui-plugins/ui-plugins/property-translators/objectlink.ts @@ -22,13 +22,13 @@ import { generateThisBacking, generateToRecord, hasDecorator, - judgeIfAddWatchFunc, + PropertyCache, + StateManagementTypes, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; -import { createOptionalClassProperty } from '../utils'; export class ObjectLinkTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { @@ -38,23 +38,19 @@ export class ObjectLinkTranslator extends PropertyTranslator implements Initiali throw new Error('@ObjectLink decorated property only accepts @Observed decorated class instance'); // TODO: replace this with proper error message. } - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); const updateStruct: arkts.AstNode = this.generateUpdateStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - currentStructInfo.updateBody.push(updateStruct); - - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { @@ -66,7 +62,7 @@ export class ObjectLinkTranslator extends PropertyTranslator implements Initiali ); const args: arkts.Expression[] = [arkts.factory.create1StringLiteral(originalName), initializers]; - judgeIfAddWatchFunc(args, this.property); + factory.judgeIfAddWatchFunc(args, this.property); const newClass = arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( @@ -117,10 +113,10 @@ export class ObjectLinkTranslator extends PropertyTranslator implements Initiali } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'ObjectLinkDecoratedVariable', + StateManagementTypes.OBJECT_LINK_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -151,3 +147,45 @@ export class ObjectLinkTranslator extends PropertyTranslator implements Initiali return false; } } + +export class ObjectLinkInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.OBJECT_LINK); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/observedTrack.ts b/arkui-plugins/ui-plugins/property-translators/observedTrack.ts index 62bcad2d6..6f77ede07 100644 --- a/arkui-plugins/ui-plugins/property-translators/observedTrack.ts +++ b/arkui-plugins/ui-plugins/property-translators/observedTrack.ts @@ -15,14 +15,27 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName } from '../../common/arkts-utils'; -import { DecoratorNames, hasDecorator } from './utils'; -import { ClassScopeInfo } from 'ui-plugins/checked-transformer'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + DecoratorNames, + hasDecorator, + StateManagementTypes, +} from './utils'; +import { ClassScopeInfo } from './types'; export class ObservedTrackTranslator { - constructor(protected property: arkts.ClassProperty, protected classScopeInfo: ClassScopeInfo) {} + protected property: arkts.ClassProperty; + protected classScopeInfo: ClassScopeInfo; + private hasImplement: boolean; + private isTracked: boolean; - private hasImplement: boolean = expectName(this.property.key).startsWith(''); - private isTracked: boolean = hasDecorator(this.property, DecoratorNames.TRACK); + constructor(property: arkts.ClassProperty, classScopeInfo: ClassScopeInfo) { + this.property = property; + this.classScopeInfo = classScopeInfo; + this.hasImplement = expectName(this.property.key).startsWith(''); + this.isTracked = hasDecorator(this.property, DecoratorNames.TRACK); + } translateMember(): arkts.AstNode[] { if (!this.isTracked && (this.classScopeInfo.classHasTrack || !this.classScopeInfo.isObserved)) { @@ -67,11 +80,9 @@ export class ObservedTrackTranslator { createGetter(originalName: string, newName: string, properyIsClass: boolean): arkts.MethodDefinition { const ifRefDepth: arkts.IfStatement = this.getterIfRefDepth(originalName); const returnMember: arkts.ReturnStatement = this.getterReturnMember(properyIsClass, newName); - const setObservationDepth = this.getterSetObservationDepth(newName); - const body = arkts.factory.createBlock([ ifRefDepth, - ...(properyIsClass ? [setObservationDepth] : []), + ...(properyIsClass ? [this.getterSetObservationDepth(newName)] : []), returnMember, ]); @@ -182,13 +193,15 @@ export class ObservedTrackTranslator { } propertyIsClassField(newName: string): arkts.ClassProperty { + collectStateManagementTypeSource(StateManagementTypes.BACKING_VALUE); + collectStateManagementTypeImport(StateManagementTypes.BACKING_VALUE); return arkts.factory.createClassProperty( arkts.factory.createIdentifier(newName), this.property.value ? arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('BackingValue'), + arkts.factory.createIdentifier(StateManagementTypes.BACKING_VALUE), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -199,7 +212,7 @@ export class ObservedTrackTranslator { : undefined, arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('BackingValue'), + arkts.factory.createIdentifier(StateManagementTypes.BACKING_VALUE), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -211,16 +224,22 @@ export class ObservedTrackTranslator { } metaField(originalName: string): arkts.ClassProperty { + collectStateManagementTypeSource(StateManagementTypes.MUTABLE_STATE_META); + collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META); return arkts.factory.createClassProperty( arkts.factory.createIdentifier(`__meta_${originalName}`), arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('MutableStateMeta')) + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.MUTABLE_STATE_META) + ) ), [arkts.factory.createStringLiteral('@Track')] ), arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('MutableStateMeta')) + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.MUTABLE_STATE_META) + ) ), arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, false @@ -267,21 +286,27 @@ export class ObservedTrackTranslator { } getterSetObservationDepth(newName: string): arkts.ExpressionStatement { + collectStateManagementTypeSource(StateManagementTypes.SET_OBSERVATION_DEPTH); + collectStateManagementTypeImport(StateManagementTypes.SET_OBSERVATION_DEPTH); return arkts.factory.createExpressionStatement( - arkts.factory.createCallExpression(arkts.factory.createIdentifier('setObservationDepth'), undefined, [ - this.genThisBackingValue(newName), - arkts.factory.createBinaryExpression( - arkts.factory.createMemberExpression( - arkts.factory.createThisExpression(), - arkts.factory.createIdentifier('_permissibleAddRefDepth'), - arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, - false, - false + arkts.factory.createCallExpression( + arkts.factory.createIdentifier(StateManagementTypes.SET_OBSERVATION_DEPTH), + undefined, + [ + this.genThisBackingValue(newName), + arkts.factory.createBinaryExpression( + arkts.factory.createMemberExpression( + arkts.factory.createThisExpression(), + arkts.factory.createIdentifier('_permissibleAddRefDepth'), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false + ), + arkts.factory.createNumericLiteral(1), + arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_MINUS ), - arkts.factory.createNumericLiteral(1), - arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_MINUS - ), - ]) + ] + ) ); } diff --git a/arkui-plugins/ui-plugins/property-translators/prop.ts b/arkui-plugins/ui-plugins/property-translators/prop.ts index b8bb3d991..f1b09a65d 100644 --- a/arkui-plugins/ui-plugins/property-translators/prop.ts +++ b/arkui-plugins/ui-plugins/property-translators/prop.ts @@ -21,12 +21,16 @@ import { createSetter2, generateGetOrSetCall, generateThisBacking, - judgeIfAddWatchFunc, + StateManagementTypes, + collectStateManagementTypeSource, + collectStateManagementTypeImport, + hasDecorator, + DecoratorNames, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; -import { createOptionalClassProperty } from '../utils'; import { factory } from './factory'; export class PropTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { @@ -34,29 +38,27 @@ export class PropTranslator extends PropertyTranslator implements InitializerCon const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const mutableThis: arkts.Expression = generateThisBacking(newName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); const updateStruct: arkts.AstNode = this.generateUpdateStruct(mutableThis, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - currentStructInfo.updateBody.push(updateStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectUpdateStruct(this.structInfo.name, [updateStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'PropDecoratedVariable', + StateManagementTypes.PROP_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -113,11 +115,13 @@ export class PropTranslator extends PropertyTranslator implements InitializerCon false ), ]; - judgeIfAddWatchFunc(args, this.property); + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeSource(StateManagementTypes.PROP_DECORATED); + collectStateManagementTypeImport(StateManagementTypes.PROP_DECORATED); const right = arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('PropDecoratedVariable'), + arkts.factory.createIdentifier(StateManagementTypes.PROP_DECORATED), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -165,3 +169,45 @@ export class PropTranslator extends PropertyTranslator implements InitializerCon ); } } + +export class PropInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.PROP)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.PROP)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `PropDecoratedVariable | undefined`. + * + * @param method expecting getter with `@Prop` and a setter with `@Prop` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.PROP); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `PropDecoratedVariable | undefined`. + * + * @param property expecting property with `@Prop`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROP); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/provide.ts b/arkui-plugins/ui-plugins/property-translators/provide.ts index 144d1239a..b084201c8 100644 --- a/arkui-plugins/ui-plugins/property-translators/provide.ts +++ b/arkui-plugins/ui-plugins/property-translators/provide.ts @@ -16,44 +16,45 @@ import * as arkts from '@koalaui/libarkts'; import { - generateToRecord, createGetter, + generateToRecord, + StateManagementTypes, createSetter2, generateThisBacking, generateGetOrSetCall, getValueInProvideAnnotation, ProvideOptions, + hasDecorator, + DecoratorNames, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; -import { createOptionalClassProperty } from '../utils'; import { factory } from './factory'; 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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(originalName, newName); - currentStructInfo.initializeBody.push(initializeStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'ProvideDecoratedVariable', + StateManagementTypes.PROVIDE_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -103,3 +104,45 @@ export class ProvideTranslator extends PropertyTranslator implements Initializer return arkts.factory.createExpressionStatement(assign); } } + +export class ProvideInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.PROVIDE); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts index d89b471e7..a059055f4 100644 --- a/arkui-plugins/ui-plugins/property-translators/regularProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/regularProperty.ts @@ -15,37 +15,34 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, generateToRecord, generateThisBacking, createSetter2 } from './utils'; -import { PropertyTranslator } from './base'; +import { createGetter, generateToRecord, generateThisBacking, createSetter2, PropertyCache } from './utils'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; -import { createOptionalClassProperty } from '../utils'; import { backingField, expectName } from '../../common/arkts-utils'; import { factory } from './factory'; -export class regularPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { +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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - '', + undefined, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, false); @@ -53,7 +50,7 @@ export class regularPropertyTranslator extends PropertyTranslator implements Ini arkts.factory.createAssignmentExpression( thisValue, arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - arkts.factory.createIdentifier('value'), + arkts.factory.createIdentifier('value') ) ); const getter: arkts.MethodDefinition = this.translateGetter( @@ -103,3 +100,13 @@ export class regularPropertyTranslator extends PropertyTranslator implements Ini return arkts.factory.createExpressionStatement(assign); } } + +export class RegularInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + return true; + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/state.ts b/arkui-plugins/ui-plugins/property-translators/state.ts index 667fabac7..b072d83e9 100644 --- a/arkui-plugins/ui-plugins/property-translators/state.ts +++ b/arkui-plugins/ui-plugins/property-translators/state.ts @@ -21,38 +21,44 @@ import { createSetter2, generateThisBacking, generateGetOrSetCall, - judgeIfAddWatchFunc, + hasDecorator, + DecoratorNames, + removeDecorator, + decoratorTypeMap, + StateManagementTypes, + collectStateManagementTypeImport, + collectStateManagementTypeSource, + PropertyCache, } from './utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; -import { createOptionalClassProperty } from '../utils'; +import { CustomComponentNames } from '../utils'; import { factory } from './factory'; +import { factory as uiFactory } from '../ui-factory'; 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); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = createOptionalClassProperty( + const field: arkts.ClassProperty = factory.createOptionalClassProperty( newName, this.property, - 'StateDecoratedVariable', + StateManagementTypes.STATE_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -93,18 +99,20 @@ export class StateTranslator extends PropertyTranslator implements InitializerCo generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { const binaryItem = arkts.factory.createBinaryExpression( factory.createBlockStatementForOptionalExpression( - arkts.factory.createIdentifier('initializers'), + arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_INITIALIZERS_NAME), originalName ), this.property.value ?? arkts.factory.createUndefinedLiteral(), arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_NULLISH_COALESCING ); const args: arkts.Expression[] = [arkts.factory.create1StringLiteral(originalName), binaryItem]; - judgeIfAddWatchFunc(args, this.property); + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeSource(StateManagementTypes.STATE_DECORATED); + collectStateManagementTypeImport(StateManagementTypes.STATE_DECORATED); const right = arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('StateDecoratedVariable'), + arkts.factory.createIdentifier(StateManagementTypes.STATE_DECORATED), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -120,3 +128,45 @@ export class StateTranslator extends PropertyTranslator implements InitializerCo return arkts.factory.createExpressionStatement(assign); } } + +export class StateInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STATE); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/storageProp.ts b/arkui-plugins/ui-plugins/property-translators/storageProp.ts index 2693f749d..2f12c29c9 100644 --- a/arkui-plugins/ui-plugins/property-translators/storageProp.ts +++ b/arkui-plugins/ui-plugins/property-translators/storageProp.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName } from '../../common/arkts-utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { DecoratorNames, @@ -25,9 +25,13 @@ import { createSetter2, generateThisBacking, generateGetOrSetCall, - judgeIfAddWatchFunc, + StateManagementTypes, + collectStateManagementTypeSource, + collectStateManagementTypeImport, + hasDecorator, + PropertyCache, } from './utils'; -import { createOptionalClassProperty } from '../utils'; +import { factory } from './factory'; function getStoragePropValueStr(node: arkts.AstNode): string | undefined { if (!arkts.isClassProperty(node) || !node.value) return undefined; @@ -63,21 +67,17 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { @@ -91,12 +91,13 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial arkts.factory.create1StringLiteral(originalName), this.property.value ?? arkts.factory.createUndefinedLiteral(), ]; - judgeIfAddWatchFunc(args, this.property); - + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeSource(StateManagementTypes.STORAGE_PROP_DECORATED); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_PROP_DECORATED); const newClass = arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('StoragePropDecoratedVariable'), + arkts.factory.createIdentifier(StateManagementTypes.STORAGE_PROP_DECORATED), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -119,10 +120,10 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = createOptionalClassProperty( + const field = factory.createOptionalClassProperty( newName, this.property, - 'StoragePropDecoratedVariable', + StateManagementTypes.STORAGE_PROP_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -159,3 +160,45 @@ export class StoragePropTranslator extends PropertyTranslator implements Initial return createSetter2(originalName, typeAnnotation, statement); } } + +export class StoragePropInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + static canBeTranslated(node: arkts.AstNode): node is InterfacePropertyTypes { + if (arkts.isMethodDefinition(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP)) { + return true; + } else if (arkts.isClassProperty(node) && hasDecorator(node, DecoratorNames.STORAGE_PROP)) { + return true; + } + return false; + } + + /** + * Wrap getter's return type and setter's param type (expecting an union type with `T` and `undefined`) + * to `StoragePropDecoratedVariable | undefined`. + * + * @param method expecting getter with `@StorageProp` and a setter with `@StorageProp` in the overloads. + */ + private updateStateMethodInInterface(method: arkts.MethodDefinition): arkts.MethodDefinition { + return factory.wrapStateManagementTypeToMethodInInterface(method, DecoratorNames.STORAGE_PROP); + } + + /** + * Wrap to the type of the property (expecting an union type with `T` and `undefined`) + * to `StoragePropDecoratedVariable | undefined`. + * + * @param property expecting property with `@StorageProp`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STORAGE_PROP); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/storagelink.ts b/arkui-plugins/ui-plugins/property-translators/storagelink.ts index efd83e9d6..4ae94c30b 100644 --- a/arkui-plugins/ui-plugins/property-translators/storagelink.ts +++ b/arkui-plugins/ui-plugins/property-translators/storagelink.ts @@ -16,7 +16,7 @@ import * as arkts from '@koalaui/libarkts'; import { backingField, expectName } from '../../common/arkts-utils'; -import { PropertyTranslator } from './base'; +import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { DecoratorNames, @@ -25,9 +25,13 @@ import { createSetter2, generateThisBacking, generateGetOrSetCall, - judgeIfAddWatchFunc, + StateManagementTypes, + collectStateManagementTypeSource, + collectStateManagementTypeImport, + hasDecorator, + PropertyCache, } from './utils'; -import { createOptionalClassProperty } from '../utils'; +import { factory } from './factory'; function getStorageLinkValueStr(node: arkts.AstNode): string | undefined { if (!arkts.isClassProperty(node) || !node.value) return undefined; @@ -63,21 +67,17 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); - this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point... + this.cacheTranslatedInitializer(newName, originalName); return this.translateWithoutInitializer(newName, originalName); } cacheTranslatedInitializer(newName: string, originalName: string): void { - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName); const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - currentStructInfo.initializeBody.push(initializeStruct); - - if (currentStructInfo.isReusable) { + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!!this.structInfo.annotations?.reusable) { const toRecord = generateToRecord(newName, originalName); - currentStructInfo.toRecordBody.push(toRecord); + PropertyCache.getInstance().collectToRecord(this.structInfo.name, [toRecord]); } - - arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo); } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { @@ -91,12 +91,13 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial arkts.factory.create1StringLiteral(originalName), this.property.value ?? arkts.factory.createUndefinedLiteral(), ]; - judgeIfAddWatchFunc(args, this.property); - + factory.judgeIfAddWatchFunc(args, this.property); + collectStateManagementTypeSource(StateManagementTypes.STORAGE_LINK_DECORATED); + collectStateManagementTypeImport(StateManagementTypes.STORAGE_LINK_DECORATED); const newClass = arkts.factory.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('StorageLinkDecoratedVariable'), + arkts.factory.createIdentifier(StateManagementTypes.STORAGE_LINK_DECORATED), arkts.factory.createTSTypeParameterInstantiation( this.property.typeAnnotation ? [this.property.typeAnnotation] : [] ) @@ -119,10 +120,10 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field = createOptionalClassProperty( + const field = factory.createOptionalClassProperty( newName, this.property, - 'StorageLinkDecoratedVariable', + StateManagementTypes.STORAGE_LINK_DECORATED, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE ); const thisValue: arkts.Expression = generateThisBacking(newName, false, true); @@ -159,3 +160,45 @@ export class StorageLinkTranslator extends PropertyTranslator implements Initial return createSetter2(originalName, typeAnnotation, statement); } } + +export class StorageLinkInterfaceTranslator extends InterfacePropertyTranslator { + translateProperty(): T { + if (arkts.isMethodDefinition(this.property)) { + this.modified = true; + return this.updateStateMethodInInterface(this.property) as T; + } else if (arkts.isClassProperty(this.property)) { + this.modified = true; + return this.updateStatePropertyInInterface(this.property) as T; + } + return this.property; + } + + 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; + } + 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 { + return factory.wrapStateManagementTypeToMethodInInterface(method, 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`. + */ + private updateStatePropertyInInterface(property: arkts.ClassProperty): arkts.ClassProperty { + return factory.wrapStateManagementTypeToPropertyInInterface(property, DecoratorNames.STORAGE_LINK); + } +} diff --git a/arkui-plugins/ui-plugins/property-translators/types.ts b/arkui-plugins/ui-plugins/property-translators/types.ts index b791a7da1..24e9e3bf6 100644 --- a/arkui-plugins/ui-plugins/property-translators/types.ts +++ b/arkui-plugins/ui-plugins/property-translators/types.ts @@ -32,3 +32,9 @@ export interface InitializerConstructor { cacheTranslatedInitializer(newName: string, originalName: string): void; translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[]; } + +export type ClassScopeInfo = { + isObserved: boolean; + classHasTrack: boolean; + getters: arkts.MethodDefinition[] +}; diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 9005d8d88..62b1583f3 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -14,8 +14,15 @@ */ import * as arkts from '@koalaui/libarkts'; -import { annotation } from '../../common/arkts-utils'; -import { factory } from './factory'; +import { DeclarationCollector } from '../../common/declaration-collector'; +import { ImportCollector } from '../import-collector'; +import { ARKUI_COMPONENT_IMPORT_NAME, ARKUI_STATEMANAGEMENT_IMPORT_NAME } from '../../common/predefines'; +import { + addMemoAnnotation, + findCanAddMemoFromParamExpression, + findCanAddMemoFromTypeAnnotation, + findImportSource, +} from '../utils'; export enum DecoratorNames { STATE = 'State', @@ -34,23 +41,128 @@ export enum DecoratorNames { LOCAL_STORAGE_PROP = 'LocalStorageProp', LOCAL_STORAGE_LINK = 'LocalStorageLink', REUSABLE = 'Reusable', - TRACK = 'Track' + TRACK = 'Track', } -export function collectPropertyDecorators(property: arkts.ClassProperty): string[] { - const properties: string[] = []; - property.annotations.forEach((anno) => { - if (!!anno.expr && arkts.isIdentifier(anno.expr)) { - properties.push(anno.expr.name); - } - }); - return properties; +export enum DecoratorIntrinsicNames { + LINK = '__Link_intrinsic', +} + +export enum DecoratorDeclarationNames { + STMT_COMMON = 'arkui.stateManagement.common', + COMP_COMMON = 'arkui.component.common', + CUSTOM_COMP = 'arkui.component.customComponent', +} + +export enum StateManagementTypes { + STATE_DECORATED = 'StateDecoratedVariable', + LINK_DECORATED = 'LinkDecoratedVariable', + STORAGE_LINK_DECORATED = 'StorageLinkDecoratedVariable', + STORAGE_PROP_DECORATED = 'StoragePropDecoratedVariable', + DECORATED_V1 = 'DecoratedV1VariableBase', + PROP_DECORATED = 'PropDecoratedVariable', + MUTABLE_STATE = 'MutableState', + MUTABLE_STATE_META = 'MutableStateMeta', + SYNCED_PROPERTY = 'SyncedProperty', + PROVIDE_DECORATED = 'ProvideDecoratedVariable', + CONSUME_DECORATED = 'ConsumeDecoratedVariable', + OBJECT_LINK_DECORATED = 'ObjectLinkDecoratedVariable', + BACKING_VALUE = 'BackingValue', + SET_OBSERVATION_DEPTH = 'setObservationDepth', + OBSERVED_OBJECT = 'IObservedObject', + WATCH_ID_TYPE = 'WatchIdType', + SUBSCRIBED_WATCHES = 'SubscribedWatches', + STORAGE_LINK_STATE = 'StorageLinkState', + OBSERVABLE_PROXY = 'observableProxy', + PROP_STATE = 'propState', + INT_32 = 'int32', +} + +export interface DecoratorInfo { + annotation: arkts.AnnotationUsage; + name: DecoratorNames; +} + +export const decoratorTypeMap = new Map([ + [DecoratorNames.STATE, StateManagementTypes.STATE_DECORATED], + [DecoratorNames.LINK, StateManagementTypes.DECORATED_V1], + [DecoratorNames.PROP, StateManagementTypes.PROP_DECORATED], + [DecoratorNames.STORAGE_LINK, StateManagementTypes.STORAGE_LINK_DECORATED], + [DecoratorNames.STORAGE_PROP, StateManagementTypes.STORAGE_PROP_DECORATED], + [DecoratorNames.LOCAL_STORAGE_PROP, StateManagementTypes.SYNCED_PROPERTY], + [DecoratorNames.LOCAL_STORAGE_LINK, StateManagementTypes.MUTABLE_STATE], + [DecoratorNames.OBJECT_LINK, StateManagementTypes.OBJECT_LINK_DECORATED], + [DecoratorNames.PROVIDE, StateManagementTypes.PROVIDE_DECORATED], + [DecoratorNames.CONSUME, StateManagementTypes.CONSUME_DECORATED], +]); + +export function isFromDecoratorDeclaration(value: any): value is DecoratorDeclarationNames { + return Object.values(DecoratorDeclarationNames).includes(value); } -export function isDecoratorAnnotation(anno: arkts.AnnotationUsage, decoratorName: DecoratorNames): boolean { +export function getImportSourceFromDeclarationName(name: DecoratorDeclarationNames): string { + if (name === DecoratorDeclarationNames.STMT_COMMON) { + return ARKUI_STATEMANAGEMENT_IMPORT_NAME; + } + return ARKUI_COMPONENT_IMPORT_NAME; +} + +export function isDecoratorIntrinsicAnnotation( + anno: arkts.AnnotationUsage, + decoratorName: DecoratorIntrinsicNames +): boolean { return !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName; } +export function isDecoratorAnnotation( + anno: arkts.AnnotationUsage, + 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); + if (!decl) return false; + const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + if (!isFromDecoratorDeclaration(moduleName)) return false; + ImportCollector.getInstance().collectSource(decoratorName, getImportSourceFromDeclarationName(moduleName)); + DeclarationCollector.getInstance().collect(decl); + } + return true; +} + +export function removeDecorator( + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, + decoratorName: DecoratorNames, + ignoreDecl?: boolean +): void { + if (arkts.isMethodDefinition(property)) { + property.scriptFunction.setAnnotations( + property.scriptFunction.annotations.filter( + (anno) => !isDecoratorAnnotation(anno, decoratorName, ignoreDecl) + ) + ); + } else { + property.setAnnotations( + property.annotations.filter((anno) => !isDecoratorAnnotation(anno, decoratorName, ignoreDecl)) + ); + } +} + +/** + * checking whether astNode's annotations contain given corresponding decorator name, + * regardless where the annotation's declaration is from arkui declaration files. + */ +export function hasDecoratorName( + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, + decoratorName: DecoratorNames +): boolean { + if (arkts.isMethodDefinition(property)) { + return property.scriptFunction.annotations.some((anno) => isDecoratorAnnotation(anno, decoratorName, true)); + } + return property.annotations.some((anno) => isDecoratorAnnotation(anno, decoratorName, true)); +} + export function hasDecorator( property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, decoratorName: DecoratorNames @@ -61,38 +173,68 @@ export function hasDecorator( return property.annotations.some((anno) => isDecoratorAnnotation(anno, decoratorName)); } -export function getStateManagementType(node: arkts.ClassProperty): string { - if (hasDecorator(node, DecoratorNames.STATE)) { - return 'StateDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.LINK)) { - return 'DecoratedV1VariableBase'; - } else if (hasDecorator(node, DecoratorNames.PROP)) { - return 'PropDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.STORAGE_LINK)) { - return 'StorageLinkDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.STORAGE_PROP)) { - return 'StoragePropDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.PROVIDE)) { - return 'ProvideDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.CONSUME)) { - return 'ConsumeDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.OBJECT_LINK)) { - return 'ObjectLinkDecoratedVariable'; - } else if (hasDecorator(node, DecoratorNames.LOCAL_STORAGE_PROP)) { - return 'SyncedProperty'; +export function findDecoratorByName( + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, + decoratorName: DecoratorNames +): arkts.AnnotationUsage | undefined { + if (arkts.isMethodDefinition(property)) { + return property.scriptFunction.annotations.find((anno) => isDecoratorAnnotation(anno, decoratorName, true)); + } + return property.annotations.find((anno) => isDecoratorAnnotation(anno, decoratorName, true)); +} + +export function findDecorator( + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition, + decoratorName: DecoratorNames +): arkts.AnnotationUsage | undefined { + if (arkts.isMethodDefinition(property)) { + return property.scriptFunction.annotations.find((anno) => isDecoratorAnnotation(anno, decoratorName)); + } + return property.annotations.find((anno) => isDecoratorAnnotation(anno, decoratorName)); +} + +export function findDecoratorInfos( + property: arkts.ClassProperty | arkts.ClassDefinition | arkts.MethodDefinition +): DecoratorInfo[] { + const decoratorNames = Object.values(DecoratorNames); + const infos: DecoratorInfo[] = []; + for (let i = 0; i < decoratorNames.length; i++) { + const name = decoratorNames[i]; + const annotation: arkts.AnnotationUsage | undefined = findDecoratorByName(property, name); + if (!!annotation) { + infos.push({ annotation, name }); + } } - return 'MutableState'; + return infos; +} + +export function getStateManagementType(decoratorInfo: DecoratorInfo): StateManagementTypes { + const decoratorName = decoratorInfo.name; + const typeName = decoratorTypeMap.get(decoratorName); + if (!!typeName) { + return typeName; + } + return StateManagementTypes.MUTABLE_STATE; +} + +export function collectStateManagementTypeImport(type: StateManagementTypes): void { + ImportCollector.getInstance().collectImport(type); +} + +export function collectStateManagementTypeSource(type: StateManagementTypes): void { + const source = findImportSource(type); + ImportCollector.getInstance().collectSource(type, source); } export function createGetter( name: string, type: arkts.TypeNode | undefined, returns: arkts.Expression, - needMemo: boolean = false, + needMemo: boolean = false ): arkts.MethodDefinition { const returnType: arkts.TypeNode | undefined = type?.clone(); - if (needMemo) { - returnType?.setAnnotations([annotation('memo')]); + if (needMemo && findCanAddMemoFromTypeAnnotation(returnType)) { + addMemoAnnotation(returnType); } const body = arkts.factory.createBlock([arkts.factory.createReturnStatement(returns)]); const scriptFunction = arkts.factory.createScriptFunction( @@ -130,8 +272,8 @@ export function createSetter( arkts.factory.createIdentifier('value', type?.clone()), undefined ); - if (needMemo) { - param.annotations = [annotation('memo')]; + if (needMemo && findCanAddMemoFromParamExpression(param)) { + addMemoAnnotation(param); } const scriptFunction = arkts.factory.createScriptFunction( body, @@ -279,15 +421,6 @@ function getDifferentAnnoTypeValue(value: arkts.Expression): string | boolean { return value.dumpSrc(); } -export function 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)); - } - } -} - export function generateGetOrSetCall(beforCall: arkts.AstNode, type: string) { return arkts.factory.createCallExpression( arkts.factory.createMemberExpression( @@ -307,12 +440,12 @@ export function generateToRecord(newName: string, originalName: string): arkts.P return arkts.Property.createProperty( 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.factory.createMemberExpression( + arkts.factory.createIdentifier('paramsCasted'), + arkts.factory.createIdentifier(originalName), + arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS, + false, + false ), arkts.ETSNewClassInstanceExpression.createETSNewClassInstanceExpression( arkts.factory.createTypeReference( @@ -325,25 +458,59 @@ export function generateToRecord(newName: string, originalName: string): arkts.P ); } -export function getStageManagementIdent(property: arkts.ClassProperty): string { - const useMutableState: boolean = - hasDecorator(property, DecoratorNames.STATE) || - hasDecorator(property, DecoratorNames.STORAGE_LINK) || - hasDecorator(property, DecoratorNames.PROVIDE) || - hasDecorator(property, DecoratorNames.CONSUME) || - hasDecorator(property, DecoratorNames.LINK) || - hasDecorator(property, DecoratorNames.LOCAL_STORAGE_LINK) || - hasDecorator(property, DecoratorNames.LINK); - const useSyncedProperty: boolean = - hasDecorator(property, DecoratorNames.PROP) || - hasDecorator(property, DecoratorNames.STORAGE_PROP) || - hasDecorator(property, DecoratorNames.LOCAL_STORAGE_PROP) || - hasDecorator(property, DecoratorNames.OBJECT_LINK); - if (useMutableState) { - return 'MutableState'; - } else if (useSyncedProperty) { - return 'SyncedProperty'; - } else { - return ''; - } +// CACHE +export interface PropertyCachedBody { + initializeBody?: arkts.AstNode[]; + updateBody?: arkts.AstNode[]; + toRecordBody?: arkts.Property[]; } + +export class PropertyCache { + private _cache: Map; + private static instance: PropertyCache; + + private constructor() { + this._cache = new Map(); + } + + static getInstance(): PropertyCache { + if (!this.instance) { + this.instance = new PropertyCache(); + } + return this.instance; + } + + reset(): void { + this._cache.clear(); + } + + getInitializeBody(name: string): arkts.AstNode[] { + return this._cache.get(name)?.initializeBody ?? []; + } + + getUpdateBody(name: string): arkts.AstNode[] { + return this._cache.get(name)?.updateBody ?? []; + } + + getToRecordBody(name: string): arkts.Property[] { + return this._cache.get(name)?.toRecordBody ?? []; + } + + collectInitializeStruct(name: string, initializeStruct: arkts.AstNode[]): void { + const initializeBody = this._cache.get(name)?.initializeBody ?? []; + const newInitializeBody = [...initializeBody, ...initializeStruct]; + this._cache.set(name, { ...this._cache.get(name), initializeBody: newInitializeBody }); + } + + collectUpdateStruct(name: string, updateStruct: arkts.AstNode[]): void { + const updateBody = this._cache.get(name)?.updateBody ?? []; + const newUpdateBody = [...updateBody, ...updateStruct]; + this._cache.set(name, { ...this._cache.get(name), updateBody: newUpdateBody }); + } + + collectToRecord(name: string, toRecord: arkts.Property[]): void { + const toRecordBody = this._cache.get(name)?.toRecordBody ?? []; + const newToRecordBody = [...toRecordBody, ...toRecord]; + this._cache.set(name, { ...this._cache.get(name), toRecordBody: newToRecordBody }); + } +} \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/struct-translators/factory.ts b/arkui-plugins/ui-plugins/struct-translators/factory.ts index 918d2ebac..e11d44e74 100644 --- a/arkui-plugins/ui-plugins/struct-translators/factory.ts +++ b/arkui-plugins/ui-plugins/struct-translators/factory.ts @@ -14,22 +14,54 @@ */ import * as arkts from '@koalaui/libarkts'; -import { BuilderLambdaNames, CustomComponentNames, Dollars } from '../utils'; +import { + BuilderLambdaNames, + addMemoAnnotation, + CustomComponentNames, + Dollars, + findImportSource, + getCustomComponentOptionsName, + getGettersFromClassDecl, + getTypeNameFromTypeParameter, + getTypeParamsFromClassDecl, + isCustomComponentInterface, +} from '../utils'; import { factory as uiFactory } from '../ui-factory'; -import { annotation } from '../../common/arkts-utils'; +import { factory as propertyFactory } from '../property-translators/factory'; +import { collect, filterDefined } from '../../common/arkts-utils'; +import { + classifyObservedTrack, + classifyProperty, + classifyPropertyInInterface, + ClassScopeInfo, + InterfacePropertyTranslator, + PropertyTranslator, +} from '../property-translators'; +import { CustomComponentScopeInfo, isEtsGlobalClass, isKnownMethodDefinition } from './utils'; +import { + collectStateManagementTypeImport, + collectStateManagementTypeSource, + DecoratorDeclarationNames, + DecoratorNames, + hasDecorator, + PropertyCache, + removeDecorator, + StateManagementTypes, +} from '../property-translators/utils'; +import { ProjectConfig } from '../../common/plugin-context'; +import { DeclarationCollector } from '../../common/declaration-collector'; +import { ObservedTrackTranslator } from '../../ui-plugins/property-translators/observedTrack'; +import { ImportCollector } from '../../ui-plugins/import-collector'; export class factory { /* - * create `constructor() {}`. + * update class `constructor` to private. */ - static createConstructorMethod(member: arkts.MethodDefinition): arkts.MethodDefinition { - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, - member.name, - arkts.factory.createFunctionExpression(member.scriptFunction), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, - false - ); + static setStructConstructorToPrivate(member: arkts.MethodDefinition): arkts.MethodDefinition { + member.modifiers &= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; + member.modifiers &= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PROTECTED; + member.modifiers |= arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; + return member; } /* @@ -44,23 +76,22 @@ export class factory { const updateKey: arkts.Identifier = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_BUILD); const scriptFunction: arkts.ScriptFunction = method.scriptFunction; - const updateScriptFunction = arkts.factory - .createScriptFunction( - scriptFunction.body, - arkts.FunctionSignature.createFunctionSignature( - scriptFunction.typeParams, - [ - uiFactory.createStyleParameter(typeName), - uiFactory.createContentParameter(), - uiFactory.createInitializersOptionsParameter(optionsName), - ], - arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), - false - ), - scriptFunction.flags, - scriptFunction.modifiers - ) - .setAnnotations([annotation('memo')]); + const updateScriptFunction = arkts.factory.createScriptFunction( + scriptFunction.body, + arkts.FunctionSignature.createFunctionSignature( + scriptFunction.typeParams, + [ + uiFactory.createStyleParameter(typeName), + uiFactory.createContentParameter(), + uiFactory.createInitializersOptionsParameter(optionsName), + ], + arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + false + ), + scriptFunction.flags, + scriptFunction.modifiers + ); + addMemoAnnotation(updateScriptFunction); const modifiers: arkts.Es2pandaModifierFlags = isDecl ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT @@ -79,10 +110,14 @@ export class factory { */ static generateTransformedResource( resourceNode: arkts.CallExpression, + key: arkts.Identifier, newArgs: arkts.AstNode[] ): arkts.CallExpression { const transformedKey: string = - resourceNode.expression.dumpSrc() === Dollars.DOLLAR_RESOURCE ? '_r' : '_rawfile'; + key.name === Dollars.DOLLAR_RESOURCE ? Dollars.TRANSFORM_DOLLAR_RESOURCE : Dollars.TRANSFORM_DOLLAR_RAWFILE; + const source = findImportSource(transformedKey); + ImportCollector.getInstance().collectSource(transformedKey, source); + ImportCollector.getInstance().collectImport(transformedKey); return arkts.factory.updateCallExpression( resourceNode, arkts.factory.createIdentifier(transformedKey), @@ -94,19 +129,15 @@ export class factory { /* * create __initializeStruct method. */ - static createInitializeStruct( - structInfo: arkts.StructInfo, - optionsTypeName: string, - isDecl?: boolean - ): arkts.MethodDefinition { + static createInitializeStruct(optionsTypeName: string, scope: CustomComponentScopeInfo): 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_ABSTRACT; - if (!isDecl) { - body = arkts.factory.createBlock(structInfo.initializeBody); + if (!scope.isDecl) { + body = arkts.factory.createBlock(PropertyCache.getInstance().getInitializeBody(scope.name)); modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; } const scriptFunction: arkts.ScriptFunction = arkts.factory @@ -135,19 +166,15 @@ export class factory { /* * create __updateStruct method. */ - static createUpdateStruct( - structInfo: arkts.StructInfo, - optionsTypeName: string, - isDecl?: boolean - ): arkts.MethodDefinition { + static createUpdateStruct(optionsTypeName: string, scope: CustomComponentScopeInfo): 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_ABSTRACT; - if (!isDecl) { - body = arkts.factory.createBlock(structInfo.updateBody); + if (!scope.isDecl) { + body = arkts.factory.createBlock(PropertyCache.getInstance().getUpdateBody(scope.name)); modifiers = arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; } @@ -177,12 +204,12 @@ export class factory { /* * create __toRecord method when the component is decorated with @Reusable. */ - static toRecord(optionsTypeName: string, toRecordBody: arkts.Property[]): arkts.MethodDefinition { + static createToRecord(optionsTypeName: string, scope: CustomComponentScopeInfo): arkts.MethodDefinition { const paramsCasted = factory.generateParamsCasted(optionsTypeName); const returnRecord = arkts.factory.createReturnStatement( arkts.ObjectExpression.createObjectExpression( arkts.Es2pandaAstNodeType.AST_NODE_TYPE_OBJECT_EXPRESSION, - toRecordBody, + PropertyCache.getInstance().getToRecordBody(scope.name), false ) ); @@ -278,7 +305,7 @@ export class factory { /* * add headers for animation in UICommonMethod */ - static modifyExternalComponentCommon(node: arkts.TSInterfaceDeclaration): arkts.AstNode { + static modifyExternalComponentCommon(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { const animationStart = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_START); const animationStop = factory.createAnimationMethod(BuilderLambdaNames.ANIMATION_STOP); const updatedBody = arkts.factory.updateInterfaceBody(node.body!, [ @@ -305,14 +332,12 @@ export class factory { arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier( 'value', - arkts.factory.createUnionType( - [ - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('AnimateParam')) - ), - arkts.factory.createETSUndefinedType() - ] - ) + arkts.factory.createUnionType([ + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier('AnimateParam')) + ), + arkts.factory.createETSUndefinedType(), + ]) ), undefined ), @@ -334,54 +359,289 @@ export class factory { ); } - /* - * generate XComponent(..., packageInfo: string, ...) + /** + * transform property members in custom-component class. */ - static modifyXcomponent(node: arkts.ScriptFunction): arkts.ScriptFunction { - const info = arkts.factory.createParameterDeclaration( - arkts.factory.createIdentifier( - 'packageInfo', - arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier('string') - ) - ) - ), - undefined + static tranformPropertyMembers( + propertyTranslators: PropertyTranslator[], + optionsTypeName: string, + scope: CustomComponentScopeInfo + ): arkts.AstNode[] { + const propertyMembers = propertyTranslators.map((translator) => translator.translateMember()); + const collections = []; + if (!scope.hasInitializeStruct) { + collections.push(this.createInitializeStruct(optionsTypeName, scope)); + } + if (!scope.hasUpdateStruct) { + collections.push(this.createUpdateStruct(optionsTypeName, scope)); + } + if (!!scope.annotations?.reusable) { + collections.push(this.createToRecord(optionsTypeName, scope)); + } + return collect(...collections, ...propertyMembers); + } + + /** + * transform non-property members in custom-component class. + */ + static transformNonPropertyMembersInClass( + member: arkts.AstNode, + classTypeName: string | undefined, + classOptionsName: string | undefined, + className: string, + isDecl?: boolean + ): arkts.AstNode { + if (arkts.isMethodDefinition(member)) { + propertyFactory.addMemoToBuilderClassMethod(member); + if (isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI) && !isDecl) { + return this.setStructConstructorToPrivate(member); + } else if (isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_BUILD_ORI)) { + return this.transformBuildMethodWithOriginBuild( + member, + classTypeName ?? className, + classOptionsName ?? getCustomComponentOptionsName(className), + isDecl + ); + } + return member; + } + return member; + } + + /** + * transform members in custom-component class. + */ + static tranformClassMembers(node: arkts.ClassDeclaration, scope: CustomComponentScopeInfo): arkts.ClassDeclaration { + if (!node.definition) { + return node; + } + let classTypeName: string | undefined; + let classOptionsName: string | undefined; + if (scope.isDecl) { + const [classType, classOptions] = getTypeParamsFromClassDecl(node); + classTypeName = getTypeNameFromTypeParameter(classType); + classOptionsName = getTypeNameFromTypeParameter(classOptions); + } + const definition: arkts.ClassDefinition = node.definition; + const className: string | undefined = node.definition.ident?.name; + if (!className) { + throw new Error('Non Empty className expected for Component'); + } + + const propertyTranslators: PropertyTranslator[] = filterDefined( + definition.body.map((it) => classifyProperty(it, scope)) ); - return arkts.factory.updateScriptFunction( - node, - node.body, - arkts.factory.createFunctionSignature( - node.typeParams, - [...node.params.slice(0, 2), info, ...node.params.slice(2)], - node.returnTypeAnnotation, - false - ), - node.flags, - node.modifiers + const translatedMembers: arkts.AstNode[] = this.tranformPropertyMembers( + propertyTranslators, + classOptionsName ?? getCustomComponentOptionsName(className), + scope ); + const updateMembers: arkts.AstNode[] = definition.body + .filter((member) => !arkts.isClassProperty(member)) + .map((member: arkts.AstNode) => + factory.transformNonPropertyMembersInClass( + member, + classTypeName, + classOptionsName, + className, + scope.isDecl + ) + ); + + const updateClassDef: arkts.ClassDefinition = this.updateCustomComponentClass(definition, [ + ...translatedMembers, + ...updateMembers, + ]); + return arkts.factory.updateClassDeclaration(node, updateClassDef); } - /* - * transform ExternalSource headers + /** + * transform `$r` and `$rawfile` function calls. */ - static transformExternalSource(externalSourceName: string, node: arkts.AstNode): arkts.AstNode { - if ( - externalSourceName === 'arkui.component.common' && - arkts.isTSInterfaceDeclaration(node) && - !!node.id && - node.id.name === 'UICommonMethod' - ) { + static transformResource( + resourceNode: arkts.CallExpression, + projectConfig: ProjectConfig | undefined + ): arkts.CallExpression { + let decl: arkts.AstNode | undefined; + if (!arkts.isIdentifier(resourceNode.expression) || !(decl = arkts.getDecl(resourceNode.expression))) { + return resourceNode; + } + DeclarationCollector.getInstance().collect(decl); + + const newArgs: arkts.AstNode[] = [ + arkts.factory.create1StringLiteral(projectConfig?.bundleName ? projectConfig.bundleName : ''), + arkts.factory.create1StringLiteral(projectConfig?.moduleName ? projectConfig.moduleName : ''), + ...resourceNode.arguments, + ]; + return this.generateTransformedResource(resourceNode, resourceNode.expression, newArgs); + } + + /** + * transform members in interface. + */ + static tranformInterfaceMembers( + node: arkts.TSInterfaceDeclaration, + externalSourceName?: string + ): arkts.TSInterfaceDeclaration { + if (!node.id || !node.body) { + return node; + } + if (externalSourceName === DecoratorDeclarationNames.COMP_COMMON && node.id.name === 'UICommonMethod') { return factory.modifyExternalComponentCommon(node); - } else if ( - externalSourceName === 'arkui.component.xcomponent' && - arkts.isScriptFunction(node) && - !!node.id && - node.id.name === 'XComponent' - ) { - return factory.modifyXcomponent(node); } + if (isCustomComponentInterface(node)) { + return factory.tranformCustomComponentInterfaceMembers(node); + } + return node; + } + + /** + * transform members in custom-component related interface. + */ + static tranformCustomComponentInterfaceMembers(node: arkts.TSInterfaceDeclaration): arkts.TSInterfaceDeclaration { + const propertyTranslators: InterfacePropertyTranslator[] = filterDefined( + node.body!.body.map((it) => classifyPropertyInInterface(it)) + ); + + let shouldUpdate: boolean = false; + const newBody = propertyTranslators.map((translator) => { + const newProperty = translator.translateProperty(); + shouldUpdate ||= translator.modified; + return newProperty; + }); + + if (shouldUpdate) { + return arkts.factory.updateInterfaceDeclaration( + node, + node.extends, + node.id, + node.typeParams, + arkts.factory.updateInterfaceBody(node.body!, newBody), + node.isStatic, + node.isFromExternal + ); + } + return node; } + + static transformNormalClass(node: arkts.ClassDeclaration): arkts.ClassDeclaration { + if (!node.definition) { + return node; + } + if (isEtsGlobalClass(node)) { + node.definition.body.forEach( + (member: arkts.AstNode) => + arkts.isMethodDefinition(member) && propertyFactory.addMemoToBuilderClassMethod(member) + ); + return node; + } + const newClassDef = factory.updateObservedTrackClassDef(node.definition); + return arkts.factory.updateClassDeclaration(node, newClassDef); + } + + static updateObservedTrackClassDef(node: arkts.ClassDefinition): arkts.ClassDefinition { + const isObserved: boolean = hasDecorator(node, DecoratorNames.OBSERVED); + const classHasTrack: boolean = node.body.some( + (member) => arkts.isClassProperty(member) && hasDecorator(member, DecoratorNames.TRACK) + ); + if (!isObserved && !classHasTrack) { + return node; + } + const updateClassDef: arkts.ClassDefinition = arkts.factory.updateClassDefinition( + node, + node.ident, + node.typeParams, + node.superTypeParams, + [ + ...node.implements, + arkts.TSClassImplements.createTSClassImplements( + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.OBSERVED_OBJECT) + ) + ) + ), + ], + undefined, + node.super, + factory.observedTrackPropertyMembers(classHasTrack, node, isObserved), + node.modifiers, + arkts.classDefinitionFlags(node) + ); + collectStateManagementTypeSource(StateManagementTypes.OBSERVED_OBJECT); + collectStateManagementTypeImport(StateManagementTypes.OBSERVED_OBJECT); + return updateClassDef; + } + + static observedTrackPropertyMembers( + classHasTrack: boolean, + definition: arkts.ClassDefinition, + isObserved: boolean + ): arkts.AstNode[] { + const watchMembers: arkts.AstNode[] = propertyFactory.createWatchMembers(); + const permissibleAddRefDepth: arkts.ClassProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier('_permissibleAddRefDepth'), + arkts.factory.createNumericLiteral(0), + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart(arkts.factory.createIdentifier(StateManagementTypes.INT_32)) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + false + ); + collectStateManagementTypeSource(StateManagementTypes.INT_32); + collectStateManagementTypeImport(StateManagementTypes.INT_32); + + const meta: arkts.ClassProperty = arkts.factory.createClassProperty( + arkts.factory.createIdentifier('__meta'), + arkts.factory.createETSNewClassInstanceExpression( + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.MUTABLE_STATE_META) + ) + ), + [arkts.factory.createStringLiteral('@Observe properties (no @Track)')] + ), + arkts.factory.createTypeReference( + arkts.factory.createTypeReferencePart( + arkts.factory.createIdentifier(StateManagementTypes.MUTABLE_STATE_META) + ) + ), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, + false + ); + collectStateManagementTypeSource(StateManagementTypes.MUTABLE_STATE_META); + collectStateManagementTypeImport(StateManagementTypes.MUTABLE_STATE_META); + + const getters: arkts.MethodDefinition[] = getGettersFromClassDecl(definition); + + const classScopeInfo: ClassScopeInfo = { + isObserved: isObserved, + classHasTrack: classHasTrack, + getters: getters, + }; + + const propertyTranslators: ObservedTrackTranslator[] = filterDefined( + definition.body.map((it) => classifyObservedTrack(it, classScopeInfo)) + ); + + const propertyMembers = propertyTranslators.map((translator) => translator.translateMember()); + + const nonClassPropertyOrGetter: arkts.AstNode[] = definition.body.filter( + (member) => + !arkts.isClassProperty(member) && + !( + arkts.isMethodDefinition(member) && + arkts.hasModifierFlag(member, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_GETTER) + ) + ); + + return [ + ...watchMembers, + ...(classHasTrack ? [permissibleAddRefDepth] : [permissibleAddRefDepth, meta]), + ...collect(...propertyMembers), + ...nonClassPropertyOrGetter, + ...classScopeInfo.getters, + ]; + } } diff --git a/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts b/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts index be9ebdb11..501e8d00a 100644 --- a/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts +++ b/arkui-plugins/ui-plugins/struct-translators/struct-transformer.ts @@ -15,205 +15,88 @@ import * as arkts from '@koalaui/libarkts'; import { AbstractVisitor } from '../../common/abstract-visitor'; -import { annotation, collect, filterDefined } from '../../common/arkts-utils'; import { ProjectConfig } from '../../common/plugin-context'; -import { classifyProperty, PropertyTranslator } from '../property-translators'; import { addMemoAnnotation, + collectCustomComponentScopeInfo, CustomComponentNames, - getCustomComponentOptionsName, - getTypeNameFromTypeParameter, - getTypeParamsFromClassDecl, + isCustomComponentClass, } from '../utils'; -import { isCustomComponentClass, isKnownMethodDefinition, isEtsGlobalClass, isReourceNode, CustomComponentScopeInfo, findCanAddMemoFromArrowFunction } from './utils'; -import { factory as uiFactory } from '../ui-factory'; +import { CustomComponentScopeInfo, findCanAddMemoFromArrowFunction, isReourceNode, ScopeInfoCollection } from './utils'; import { factory } from './factory'; import { isEntryWrapperClass } from '../entry-translators/utils'; import { factory as entryFactory } from '../entry-translators/factory'; -import { DecoratorNames, hasDecorator } from '../property-translators/utils'; -import { ScopeInfoCollection } from './utils'; - -function tranformPropertyMembers( - className: string, - propertyTranslators: PropertyTranslator[], - optionsTypeName: string, - isDecl?: boolean, - scope?: CustomComponentScopeInfo -): arkts.AstNode[] { - const propertyMembers = propertyTranslators.map((translator) => translator.translateMember()); - const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(className); - const collections = []; - if (!scope?.hasInitializeStruct) { - collections.push(factory.createInitializeStruct(currentStructInfo, optionsTypeName, isDecl)); - } - if (!scope?.hasUpdateStruct) { - collections.push(factory.createUpdateStruct(currentStructInfo, optionsTypeName, isDecl)); - } - if (currentStructInfo.isReusable) { - collections.push(factory.toRecord(optionsTypeName, currentStructInfo.toRecordBody)); - } - return collect(...collections, ...propertyMembers); -} - -function transformEtsGlobalClassMembers(node: arkts.ClassDeclaration): arkts.ClassDeclaration { - if (!node.definition) { - return node; - } - node.definition.body.map((member: arkts.AstNode) => { - if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.BUILDER)) { - member.scriptFunction.setAnnotations([annotation('memo')]); - } - return member; - }); - return node; -} - -function transformOtherMembersInClass( - member: arkts.AstNode, - classTypeName: string | undefined, - classOptionsName: string | undefined, - className: string, - isDecl?: boolean -): arkts.AstNode { - if (arkts.isMethodDefinition(member) && hasDecorator(member, DecoratorNames.BUILDER)) { - member.scriptFunction.setAnnotations([annotation('memo')]); - return member; - } - if ( - arkts.isMethodDefinition(member) && - isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_CONSTRUCTOR_ORI) && - !isDecl - ) { - return uiFactory.createConstructorMethod(member); - } - if (arkts.isMethodDefinition(member) && isKnownMethodDefinition(member, CustomComponentNames.COMPONENT_BUILD_ORI)) { - return factory.transformBuildMethodWithOriginBuild( - member, - classTypeName ?? className, - classOptionsName ?? getCustomComponentOptionsName(className), - isDecl - ); - } - return member; -} - -function tranformClassMembers( - node: arkts.ClassDeclaration, - isDecl?: boolean, - scope?: CustomComponentScopeInfo -): arkts.ClassDeclaration { - if (!node.definition) { - return node; - } - - let classTypeName: string | undefined; - let classOptionsName: string | undefined; - if (isDecl) { - const [classType, classOptions] = getTypeParamsFromClassDecl(node); - classTypeName = getTypeNameFromTypeParameter(classType); - classOptionsName = getTypeNameFromTypeParameter(classOptions); - } - const definition: arkts.ClassDefinition = node.definition; - const className: string | undefined = node.definition.ident?.name; - if (!className) { - throw new Error('Non Empty className expected for Component'); - } - - const propertyTranslators: PropertyTranslator[] = filterDefined( - definition.body.map((it) => classifyProperty(it, className)) - ); - const translatedMembers: arkts.AstNode[] = tranformPropertyMembers( - className, - propertyTranslators, - classOptionsName ?? getCustomComponentOptionsName(className), - isDecl, - scope - ); - const updateMembers: arkts.AstNode[] = definition.body - .filter((member) => !arkts.isClassProperty(member)) - .map((member: arkts.AstNode) => - transformOtherMembersInClass(member, classTypeName, classOptionsName, className, isDecl) - ); - - const updateClassDef: arkts.ClassDefinition = factory.updateCustomComponentClass(definition, [ - ...translatedMembers, - ...updateMembers, - ]); - return arkts.factory.updateClassDeclaration(node, updateClassDef); -} - -function transformResource( - resourceNode: arkts.CallExpression, - projectConfig: ProjectConfig | undefined -): arkts.CallExpression { - const newArgs: arkts.AstNode[] = [ - arkts.factory.create1StringLiteral(projectConfig?.bundleName ? projectConfig.bundleName : ''), - arkts.factory.create1StringLiteral(projectConfig?.moduleName ? projectConfig.moduleName : ''), - ...resourceNode.arguments, - ]; - return factory.generateTransformedResource(resourceNode, newArgs); -} +import { ImportCollector } from '../import-collector'; +import { PropertyCache } from '../property-translators/utils'; export class StructTransformer extends AbstractVisitor { - private scopeInfoCollection: ScopeInfoCollection; + private scope: ScopeInfoCollection; projectConfig: ProjectConfig | undefined; constructor(projectConfig: ProjectConfig | undefined) { super(); this.projectConfig = projectConfig; - this.scopeInfoCollection = { customComponents: [] }; + this.scope = { customComponents: [] }; } reset(): void { super.reset(); - this.scopeInfoCollection = { customComponents: [] }; + this.scope = { customComponents: [] }; + PropertyCache.getInstance().reset(); + ImportCollector.getInstance().reset(); } enter(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - this.scopeInfoCollection.customComponents.push({ name: node.definition!.ident!.name }); + if (arkts.isClassDeclaration(node) && !!node.definition && node.definition.body.length > 0) { + const customComponentInfo = collectCustomComponentScopeInfo(node); + if (!!customComponentInfo) { + this.scope.customComponents.push(customComponentInfo); + } } - if (arkts.isMethodDefinition(node) && this.scopeInfoCollection.customComponents.length > 0) { + if (arkts.isMethodDefinition(node) && this.scope.customComponents.length > 0) { const name = node.name.name; - const scopeInfo = this.scopeInfoCollection.customComponents.pop()!; + const scopeInfo = this.scope.customComponents.pop()!; scopeInfo.hasInitializeStruct ||= name === CustomComponentNames.COMPONENT_INITIALIZE_STRUCT; scopeInfo.hasUpdateStruct ||= name === CustomComponentNames.COMPONENT_UPDATE_STRUCT; scopeInfo.hasReusableRebind ||= name === CustomComponentNames.REUSABLE_COMPONENT_REBIND_STATE; - this.scopeInfoCollection.customComponents.push(scopeInfo); + this.scope.customComponents.push(scopeInfo); } } - exit(node: arkts.AstNode): void { - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - this.scopeInfoCollection.customComponents.pop(); + if ( + arkts.isClassDeclaration(node) && + this.scope.customComponents.length > 0 && + isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) + ) { + this.scope.customComponents.pop(); } } visitor(beforeChildren: arkts.AstNode): arkts.AstNode { this.enter(beforeChildren); const node = this.visitEachChild(beforeChildren); - if (arkts.isClassDeclaration(node) && isCustomComponentClass(node)) { - let scope: CustomComponentScopeInfo | undefined; - const scopeInfos: CustomComponentScopeInfo[] = this.scopeInfoCollection.customComponents; - if (scopeInfos.length > 0) { - scope = scopeInfos[scopeInfos.length - 1]; - } - const newClass: arkts.ClassDeclaration = tranformClassMembers( - node, - arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE), - scope - ); + if ( + arkts.isClassDeclaration(node) && + this.scope.customComponents.length > 0 && + isCustomComponentClass(node, this.scope.customComponents[this.scope.customComponents.length - 1]) + ) { + const scope: CustomComponentScopeInfo = this.scope.customComponents[this.scope.customComponents.length - 1]; + const newClass: arkts.ClassDeclaration = factory.tranformClassMembers(node, scope); this.exit(beforeChildren); return newClass; } else if (isEntryWrapperClass(node)) { entryFactory.addMemoToEntryWrapperClassMethods(node); return node; - } else if (arkts.isClassDeclaration(node) && isEtsGlobalClass(node)) { - return transformEtsGlobalClassMembers(node); + } else if (arkts.isClassDeclaration(node)) { + return factory.transformNormalClass(node); } else if (arkts.isCallExpression(node) && isReourceNode(node)) { - return transformResource(node, this.projectConfig); + return factory.transformResource(node, this.projectConfig); + } else if (arkts.isTSInterfaceDeclaration(node)) { + return factory.tranformInterfaceMembers(node, this.externalSourceName); } else if (findCanAddMemoFromArrowFunction(node)) { return addMemoAnnotation(node); + } else if (arkts.isEtsScript(node) && ImportCollector.getInstance().importInfos.length > 0) { + ImportCollector.getInstance().insertCurrentImports(this.program); } return node; } diff --git a/arkui-plugins/ui-plugins/struct-translators/utils.ts b/arkui-plugins/ui-plugins/struct-translators/utils.ts index 2af217626..139e3d726 100644 --- a/arkui-plugins/ui-plugins/struct-translators/utils.ts +++ b/arkui-plugins/ui-plugins/struct-translators/utils.ts @@ -14,7 +14,7 @@ */ import * as arkts from '@koalaui/libarkts'; -import { Dollars, isMemoAnnotation } from '../utils'; +import { CustomComponentInfo, Dollars, isMemoAnnotation, MemoNames } from '../utils'; import { CustomComponentNames } from '../utils'; import { DecoratorNames, isDecoratorAnnotation } from '../property-translators/utils'; @@ -22,27 +22,12 @@ export type ScopeInfoCollection = { customComponents: CustomComponentScopeInfo[]; }; -export type CustomComponentScopeInfo = { - name: string; +export type CustomComponentScopeInfo = CustomComponentInfo & { hasInitializeStruct?: boolean; hasUpdateStruct?: boolean; hasReusableRebind?: boolean; }; -/** - * Determine whether it is a custom component. - * - * @param node class declaration node - */ -export function isCustomComponentClass(node: arkts.ClassDeclaration): boolean { - if (!node.definition?.ident?.name) { - return false; - } - const name: string = node.definition.ident.name; - const structCollection: Set = arkts.GlobalInfo.getInfoInstance().getStructCollection(); - return name === CustomComponentNames.COMPONENT_CLASS_NAME || structCollection.has(name); -} - /** * Determine whether it is method with specified name. * @@ -72,15 +57,15 @@ export function isEtsGlobalClass(node: arkts.ClassDeclaration): boolean { } /** - * Determine whether it is resource node begin with '$r' or '$rawfile'. + * Determine whether it is resource node begin with `$r` or `$rawfile`. * * @param node call expression node */ export function isReourceNode(node: arkts.CallExpression): boolean { - if (node.expression.dumpSrc() === Dollars.DOLLAR_RESOURCE || node.expression.dumpSrc() === Dollars.DOLLAR_RAWFILE) { - return true; - } - return false; + return ( + arkts.isIdentifier(node.expression) && + (node.expression.name === Dollars.DOLLAR_RESOURCE || node.expression.name === Dollars.DOLLAR_RAWFILE) + ); } export function isMemoCall(node: arkts.AstNode): node is arkts.CallExpression { @@ -96,7 +81,7 @@ export function isMemoCall(node: arkts.AstNode): node is arkts.CallExpression { if (arkts.isMethodDefinition(decl)) { return decl.scriptFunction.annotations.some( - (anno) => isDecoratorAnnotation(anno, DecoratorNames.BUILDER) || isMemoAnnotation(anno, 'memo') + (anno) => isDecoratorAnnotation(anno, DecoratorNames.BUILDER) || isMemoAnnotation(anno, MemoNames.MEMO) ); } return false; @@ -106,7 +91,7 @@ export function findCanAddMemoFromArrowFunction(node: arkts.AstNode): node is ar if (!arkts.isArrowFunctionExpression(node)) { return false; } - const hasMemo: boolean = node.annotations.some((anno) => isMemoAnnotation(anno, 'memo')); + const hasMemo: boolean = node.annotations.some((anno) => isMemoAnnotation(anno, MemoNames.MEMO)); if (!hasMemo && !!node.scriptFunction.body && arkts.isBlockStatement(node.scriptFunction.body)) { return node.scriptFunction.body.statements.some( (st) => arkts.isExpressionStatement(st) && isMemoCall(st.expression) diff --git a/arkui-plugins/ui-plugins/ui-factory.ts b/arkui-plugins/ui-plugins/ui-factory.ts index 90fefdee5..5885848e7 100644 --- a/arkui-plugins/ui-plugins/ui-factory.ts +++ b/arkui-plugins/ui-plugins/ui-factory.ts @@ -14,10 +14,42 @@ */ import * as arkts from '@koalaui/libarkts'; -import { BuilderLambdaNames, CustomComponentNames, hasPropertyInAnnotation } from './utils'; -import { annotation } from '../common/arkts-utils'; +import { + addMemoAnnotation, + BuilderLambdaNames, + CustomComponentNames, + findCanAddMemoFromParamExpression, + hasPropertyInAnnotation, +} from './utils'; +import { PartialExcept, PartialNested, PartialNestedExcept, PickNested } from '../common/safe-types'; import { DecoratorNames } from './property-translators/utils'; +export interface ScriptFunctionConfiguration { + key: arkts.Identifier | undefined; + body: arkts.AstNode | undefined; + typeParams: arkts.TSTypeParameterDeclaration | undefined; + params: readonly arkts.Expression[]; + returnTypeAnnotation: arkts.TypeNode | undefined; + hasReceiver: boolean; + flags: arkts.Es2pandaScriptFunctionFlags; + modifiers: arkts.Es2pandaModifierFlags; + annotations: arkts.AnnotationUsage[]; +} + +export interface MethodDefinitionConfiguration { + key: arkts.Identifier; + kind: arkts.Es2pandaMethodDefinitionKind; + function: ScriptFunctionConfiguration; + overloads: arkts.MethodDefinition[]; + modifiers: arkts.Es2pandaModifierFlags; + isComputed: boolean; +} + +export interface IntrinsicAnnotationDeclarationConfiguration { + expr: arkts.Identifier; + properties: arkts.AstNode[]; +} + export class factory { /** * create `instance: ` as identifier @@ -69,8 +101,10 @@ export class factory { */ static createStyleParameter(typeName: string): arkts.ETSParameterExpression { const styleParam: arkts.Identifier = factory.createStyleIdentifier(typeName); - const param = arkts.factory.createParameterDeclaration(styleParam, undefined); - param.annotations = [annotation('memo')]; + const param: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration(styleParam, undefined); + if (findCanAddMemoFromParamExpression(param)) { + addMemoAnnotation(param); + } return param; } @@ -112,8 +146,10 @@ export class factory { */ static createContentParameter(): arkts.ETSParameterExpression { const contentParam: arkts.Identifier = factory.createContentIdentifier(); - const param = arkts.factory.createParameterDeclaration(contentParam, undefined); - param.annotations = [annotation('memo')]; + const param: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration(contentParam, undefined); + if (findCanAddMemoFromParamExpression(param)) { + addMemoAnnotation(param); + } return param; } @@ -165,7 +201,7 @@ export class factory { return; } - /* + /** * create `import { as } ...`. */ static createAdditionalImportSpecifier(imported: string, local: string): arkts.ImportSpecifier { @@ -175,59 +211,128 @@ export class factory { ); } - /* - * create `constructor() {}`. + /** + * update ScriptFunction with configurations. */ - static createConstructorMethod(member: arkts.MethodDefinition): arkts.MethodDefinition { - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_CONSTRUCTOR, - member.name, - arkts.factory.createFunctionExpression(member.scriptFunction), - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_CONSTRUCTOR, - false + static updateScriptFunction( + original: arkts.ScriptFunction, + config: Partial + ): arkts.ScriptFunction { + const newFunc: arkts.ScriptFunction = arkts.factory.updateScriptFunction( + original, + config.body ?? original.body, + arkts.factory.createFunctionSignature( + config.typeParams ?? original.typeParams, + config.params ?? original.params, + config.returnTypeAnnotation ?? original.returnTypeAnnotation, + config.hasReceiver ?? original.hasReceiver + ), + config.flags ?? original.flags, + config.modifiers ?? original.modifiers ); + if (!!config.key) { + newFunc.setIdent(config.key); + } + if (!!config.annotations) { + newFunc.setAnnotations(config.annotations); + } + return newFunc; } - /* - * create `@memo() _build(<>)`. + /** + * create ScriptFunction with configurations. */ - static transformBuildMethodWithOriginBuild( - method: arkts.MethodDefinition, - typeName: string, - optionsName: string, - isDecl?: boolean + static createScriptFunction(config: Partial) { + const newFunc: arkts.ScriptFunction = arkts.factory.createScriptFunction( + config.body ?? undefined, + arkts.factory.createFunctionSignature( + config.typeParams ?? undefined, + config.params ?? [], + config.returnTypeAnnotation ?? undefined, + config.hasReceiver ?? false + ), + config.flags ?? arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_NONE, + config.modifiers ?? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ); + if (!!config.key) { + newFunc.setIdent(config.key); + } + if (!!config.annotations) { + newFunc.setAnnotations(config.annotations); + } + return newFunc; + } + + /** + * update MethodDefinition with configurations. + */ + static updateMethodDefinition( + original: arkts.MethodDefinition, + config: PartialNested ): arkts.MethodDefinition { - const updateKey: arkts.Identifier = arkts.factory.createIdentifier(CustomComponentNames.COMPONENT_BUILD); + const key: arkts.Identifier = config.key ?? original.name; + const newFunc: arkts.ScriptFunction = factory.updateScriptFunction(original.scriptFunction, { + ...config.function, + key, + }); + const newMethod: arkts.MethodDefinition = arkts.factory.updateMethodDefinition( + original, + config.kind ?? original.kind, + key, + arkts.factory.createFunctionExpression(newFunc), + config.modifiers ?? original.modifiers, + config.isComputed ?? false // TODO: how do I get it? + ); + if (!!config.overloads) { + newMethod.setOverloads(config.overloads); + } + return newMethod; + } - const scriptFunction: arkts.ScriptFunction = method.scriptFunction; - const updateScriptFunction = arkts.factory - .createScriptFunction( - scriptFunction.body, - arkts.FunctionSignature.createFunctionSignature( - scriptFunction.typeParams, - [ - factory.createStyleParameter(typeName), - factory.createContentParameter(), - factory.createInitializersOptionsParameter(optionsName), - ], - arkts.factory.createPrimitiveType(arkts.Es2pandaPrimitiveType.PRIMITIVE_TYPE_VOID), + /** + * create MethodDefinition with configurations. + */ + static createMethodDefinition( + config: PartialNestedExcept + ): arkts.MethodDefinition { + const newFunc: arkts.ScriptFunction = factory.createScriptFunction({ + ...config.function, + key: config.key, + }); + const newMethod: arkts.MethodDefinition = arkts.factory.createMethodDefinition( + config.kind ?? arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_NONE, + config.key, + arkts.factory.createFunctionExpression(newFunc), + config.modifiers ?? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_NONE, + config.isComputed ?? false // TODO: how do I get it? + ); + if (!!config.overloads) { + newMethod.setOverloads(config.overloads); + } + return newMethod; + } + + /** + * create intrinsic `@Retention({policy:"SOURCE"})` AnnotationDeclaration with configurations. + */ + static createIntrinsicAnnotationDeclaration( + config: PartialExcept + ): arkts.AnnotationDeclaration { + const intrinsicAnnotations: arkts.AnnotationUsage[] = [ + arkts.factory.create1AnnotationUsage(arkts.factory.createIdentifier('Retention'), [ + arkts.factory.createClassProperty( + arkts.factory.createIdentifier('policy'), + arkts.factory.createStringLiteral('SOURCE'), + undefined, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, false ), - scriptFunction.flags, - scriptFunction.modifiers - ) - .setAnnotations([annotation('memo')]); - - const modifiers: arkts.Es2pandaModifierFlags = isDecl - ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_ABSTRACT - : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; - return arkts.factory.createMethodDefinition( - arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_METHOD, - updateKey, - arkts.factory.createFunctionExpression(updateScriptFunction), - modifiers, - false - ); + ]), + ]; + const newAnnotationDecl: arkts.AnnotationDeclaration = arkts.factory + .createAnnotationDeclaration(config.expr, config.properties ?? []) + .setAnnotations(intrinsicAnnotations); + return newAnnotationDecl; } /* diff --git a/arkui-plugins/ui-plugins/utils.ts b/arkui-plugins/ui-plugins/utils.ts index 73a22180b..4a657c3a1 100644 --- a/arkui-plugins/ui-plugins/utils.ts +++ b/arkui-plugins/ui-plugins/utils.ts @@ -15,12 +15,14 @@ import * as arkts from '@koalaui/libarkts'; import { annotation } from '../common/arkts-utils'; -import { DecoratorNames } from './property-translators/utils'; +import { ImportCollector } from './import-collector'; +import { ARKUI_STATEMANAGEMENT_IMPORT_NAME, IMPORT_SOURCE_MAP_V2 } from '../common/predefines'; +import { DeclarationCollector } from '../common/declaration-collector'; export enum CustomComponentNames { - ENTRY_ANNOTATION_NAME = 'Entry', - COMPONENT_ANNOTATION_NAME = 'Component', - RESUABLE_ANNOTATION_NAME = 'Reusable', + ENTRY_ANNOTATION = 'Entry', + COMPONENT_ANNOTATION = 'Component', + RESUABLE_ANNOTATION = 'Reusable', COMPONENT_BUILD_ORI = 'build', COMPONENT_CONSTRUCTOR_ORI = 'constructor', COMPONENT_DEFAULT_IMPORT = '@ohos.arkui.component', @@ -51,6 +53,21 @@ export enum Dollars { DOLLAR_RESOURCE = '$r', DOLLAR_RAWFILE = '$rawfile', DOLLAR_DOLLAR = '$$', + TRANSFORM_DOLLAR_RESOURCE = '_r', + TRANSFORM_DOLLAR_RAWFILE = '_rawfile', +} + +export enum MemoNames { + MEMO = 'memo', +} + +// IMPORT +export function findImportSource(importName: string): string { + const source = IMPORT_SOURCE_MAP_V2.get(importName); + if (!source) { + throw new Error(`cannot find "${importName}" in the import source map.`); + } + return source; } export function findLocalImport( @@ -67,22 +84,12 @@ export function findLocalImport( return importSpecifier?.local ?? importSpecifier?.imported; } -// TODO: currently, we forcely assume initializerOptions is named in pattern __Options_xxx -export function getCustomComponentNameFromInitializerOptions(name: string): string | undefined { - const prefix: string = CustomComponentNames.COMPONENT_INTERFACE_PREFIX; - if (name.startsWith(prefix)) { - return name.substring(prefix.length); - } -} - -export function getCustomComponentOptionsName(className: string): string { - return `${CustomComponentNames.COMPONENT_INTERFACE_PREFIX}${className}`; -} - +// AST NODE export function isStatic(node: arkts.AstNode): boolean { return node.isStatic; } +// TYPE PARAMETER export function getTypeParamsFromClassDecl(node: arkts.ClassDeclaration | undefined): readonly arkts.TSTypeParameter[] { return node?.definition?.typeParams?.params ?? []; } @@ -91,41 +98,7 @@ export function getTypeNameFromTypeParameter(node: arkts.TSTypeParameter | undef return node?.name?.name; } -export function createOptionalClassProperty( - name: string, - property: arkts.ClassProperty, - stageManagementIdent: string, - modifiers: arkts.Es2pandaModifierFlags, - needMemo: boolean = false -): arkts.ClassProperty { - const newType: arkts.TypeNode | undefined = property.typeAnnotation?.clone(); - if (needMemo) { - newType?.setAnnotations([annotation('memo')]); - } - const newProperty = arkts.factory.createClassProperty( - arkts.factory.createIdentifier(name), - undefined, - stageManagementIdent.length ? createStageManagementType(stageManagementIdent, property) : newType, - modifiers, - false - ); - return arkts.classPropertySetOptional(newProperty, true); -} - -export function createStageManagementType( - stageManagementIdent: string, - property: arkts.ClassProperty -): arkts.ETSTypeReference { - return arkts.factory.createTypeReference( - arkts.factory.createTypeReferencePart( - arkts.factory.createIdentifier(stageManagementIdent), - arkts.factory.createTSTypeParameterInstantiation([ - property.typeAnnotation ? property.typeAnnotation.clone() : arkts.factory.createETSUndefinedType(), - ]) - ) - ); -} - +// GETTER export function getGettersFromClassDecl(definition: arkts.ClassDefinition): arkts.MethodDefinition[] { return definition.body.filter( (member) => @@ -134,6 +107,127 @@ export function getGettersFromClassDecl(definition: arkts.ClassDefinition): arkt ) as arkts.MethodDefinition[]; } +// ANNOTATION +export function hasPropertyInAnnotation(annotation: arkts.AnnotationUsage, propertyName: string): boolean { + return !!annotation.properties.find( + (annoProp: arkts.AstNode) => + arkts.isClassProperty(annoProp) && + annoProp.key && + arkts.isIdentifier(annoProp.key) && + annoProp.key.name === propertyName + ); +} + +// CUSTOM COMPONENT +export type CustomComponentInfo = { + name: string; + isDecl: boolean; + annotations: CustomComponentAnontations; +}; + +export type CustomComponentAnontations = { + component?: arkts.AnnotationUsage; + entry?: arkts.AnnotationUsage; + reusable?: arkts.AnnotationUsage; +}; + +export function isCustomComponentAnnotation( + anno: arkts.AnnotationUsage, + decoratorName: CustomComponentNames, + ignoreDecl?: boolean +): boolean { + if (!(!!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === decoratorName)) return false; + if (!ignoreDecl) { + const decl = arkts.getDecl(anno.expr); + if (!decl) return false; + const moduleName: string = arkts.getProgramFromAstNode(decl).moduleName; + if (!moduleName) return false; + DeclarationCollector.getInstance().collect(decl); + } + return true; +} + +export function collectCustomComponentScopeInfo( + node: arkts.ClassDeclaration | arkts.StructDeclaration +): CustomComponentInfo | undefined { + const definition: arkts.ClassDefinition | undefined = node.definition; + if (!definition || !definition?.ident?.name) { + return undefined; + } + const isStruct = arkts.isStructDeclaration(node); + const isDecl: boolean = arkts.hasModifierFlag(node, arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_DECLARE); + const isCustomComponentClassDecl = !isStruct && isDecl; + const shouldIgnoreDecl = isStruct || isDecl; + if (isCustomComponentClassDecl && definition.ident.name !== CustomComponentNames.COMPONENT_CLASS_NAME) { + return undefined; + } + let annotations: CustomComponentAnontations = {}; + if (!isCustomComponentClassDecl) { + let isCustomComponent: boolean = false; + for (const anno of definition.annotations) { + const isComponent = isCustomComponentAnnotation( + anno, + CustomComponentNames.COMPONENT_ANNOTATION, + shouldIgnoreDecl + ); + const isEntry = isCustomComponentAnnotation(anno, CustomComponentNames.ENTRY_ANNOTATION, shouldIgnoreDecl); + const isReusable = isCustomComponentAnnotation( + anno, + CustomComponentNames.RESUABLE_ANNOTATION, + shouldIgnoreDecl + ); + isCustomComponent ||= isComponent; + annotations = { + ...annotations, + ...(isComponent && !annotations?.component && { component: anno }), + ...(isEntry && !annotations?.entry && { entry: anno }), + ...(isReusable && !annotations?.reusable && { reusable: anno }), + }; + } + if (!isCustomComponent) { + return undefined; + } + } + return { + name: definition.ident.name, + isDecl, + annotations: annotations as CustomComponentAnontations, + }; +} + +export function isComponentStruct(node: arkts.StructDeclaration, scopeInfo: CustomComponentInfo): boolean { + return scopeInfo.name === node.definition.ident?.name; +} + +/** + * Determine whether it is a custom component. + * + * @param node class declaration node + */ +export function isCustomComponentClass(node: arkts.ClassDeclaration, scopeInfo: CustomComponentInfo): boolean { + if (!node.definition?.ident?.name) { + return false; + } + const name: string = node.definition.ident.name; + if (scopeInfo.isDecl) { + return name === CustomComponentNames.COMPONENT_CLASS_NAME; + } + return name === scopeInfo.name; +} + +export function isCustomComponentInterface(node: arkts.TSInterfaceDeclaration): boolean { + const checkPrefix = !!node.id?.name.startsWith(CustomComponentNames.COMPONENT_INTERFACE_PREFIX); + const checkComponent = node.annotations.some((anno) => + isCustomComponentAnnotation(anno, CustomComponentNames.COMPONENT_ANNOTATION) + ); + return checkPrefix && checkComponent; +} + +export function getCustomComponentOptionsName(className: string): string { + return `${CustomComponentNames.COMPONENT_INTERFACE_PREFIX}${className}`; +} + +// MEMO export type MemoAstNode = | arkts.ScriptFunction | arkts.ETSParameterExpression @@ -143,14 +237,56 @@ export type MemoAstNode = | arkts.ArrowFunctionExpression | arkts.ETSUnionType; -export function isMemoAnnotation(node: arkts.AnnotationUsage, memoName: string): boolean { +export function hasMemoAnnotation(node: T): boolean { + return node.annotations.some((it) => isMemoAnnotation(it, MemoNames.MEMO)); +} + +export function collectMemoAnnotationImport(memoName: MemoNames = MemoNames.MEMO): void { + ImportCollector.getInstance().collectImport(memoName); +} + +export function collectMemoAnnotationSource(memoName: MemoNames = MemoNames.MEMO): void { + if (memoName === MemoNames.MEMO) { + ImportCollector.getInstance().collectSource(memoName, ARKUI_STATEMANAGEMENT_IMPORT_NAME); + } +} + +export function findCanAddMemoFromTypeAnnotation( + typeAnnotation: arkts.AstNode | undefined +): typeAnnotation is arkts.ETSFunctionType { + if (!typeAnnotation) { + return false; + } + if (arkts.isETSFunctionType(typeAnnotation)) { + return true; + } else if (arkts.isETSUnionType(typeAnnotation)) { + return typeAnnotation.types.some((type) => arkts.isETSFunctionType(type)); + } + return false; +} + +export function findCanAddMemoFromParamExpression( + param: arkts.AstNode | undefined +): param is arkts.ETSParameterExpression { + if (!param) { + return false; + } + if (!arkts.isEtsParameterExpression(param)) { + return false; + } + const type = param.type; + return findCanAddMemoFromTypeAnnotation(type); +} + +export function isMemoAnnotation(node: arkts.AnnotationUsage, memoName: MemoNames): boolean { if (!(node.expr !== undefined && arkts.isIdentifier(node.expr) && node.expr.name === memoName)) { return false; } return true; } -export function addMemoAnnotation(node: T, memoName: string = 'memo'): T { +export function addMemoAnnotation(node: T, memoName: MemoNames = MemoNames.MEMO): T { + collectMemoAnnotationSource(memoName); if (arkts.isETSUnionType(node)) { const functionType = node.types.find((type) => arkts.isETSFunctionType(type)); if (!functionType) { @@ -163,19 +299,10 @@ export function addMemoAnnotation(node: T, memoName: stri ...node.annotations.filter((it) => !isMemoAnnotation(it, memoName)), annotation(memoName), ]; + collectMemoAnnotationImport(memoName); if (arkts.isEtsParameterExpression(node)) { node.annotations = newAnnotations; return node; } return node.setAnnotations(newAnnotations) as T; } - -export function hasPropertyInAnnotation(annotation: arkts.AnnotationUsage, propertyName: string): boolean { - return !!annotation.properties.find( - (annoProp: arkts.AstNode) => - arkts.isClassProperty(annoProp) && - annoProp.key && - arkts.isIdentifier(annoProp.key) && - annoProp.key.name === propertyName - ); -} \ No newline at end of file diff --git a/koala-wrapper/native/include/common.h b/koala-wrapper/native/include/common.h index 77ed29cf8..399d28d22 100644 --- a/koala-wrapper/native/include/common.h +++ b/koala-wrapper/native/include/common.h @@ -32,7 +32,7 @@ string getString(KStringPtr ptr); char* getStringCopy(KStringPtr& ptr); -inline KUInt unpackUInt(const KByte* bytes); +KUInt unpackUInt(const KByte* bytes); es2panda_ContextState intToState(KInt state); diff --git a/koala-wrapper/native/src/bridges.cc b/koala-wrapper/native/src/bridges.cc index 31984c2dd..6dba4da14 100644 --- a/koala-wrapper/native/src/bridges.cc +++ b/koala-wrapper/native/src/bridges.cc @@ -15,6 +15,28 @@ #include "common.h" +#include +#include +#include + +std::set globalStructInfo; +std::mutex structMutex; + +void impl_InsertGlobalStructInfo(KNativePointer contextPtr, KStringPtr& instancePtr) +{ + std::lock_guard lock(structMutex); + globalStructInfo.insert(getStringCopy(instancePtr)); + return; +} +KOALA_INTEROP_V2(InsertGlobalStructInfo, KNativePointer, KStringPtr); + +KBoolean impl_HasGlobalStructInfo(KNativePointer contextPtr, KStringPtr& instancePtr) +{ + std::lock_guard lock(structMutex); + return globalStructInfo.count(getStringCopy(instancePtr)); +} +KOALA_INTEROP_2(HasGlobalStructInfo, KBoolean, KNativePointer, KStringPtr); + KBoolean impl_ClassDefinitionIsFromStructConst(KNativePointer contextPtr, KNativePointer instancePtr) { auto context = reinterpret_cast(contextPtr); @@ -178,7 +200,7 @@ KOALA_INTEROP_1(ContextProgram, KNativePointer, KNativePointer) KNativePointer impl_ProgramAst(KNativePointer contextPtr, KNativePointer programPtr) { - auto context = reinterpret_cast(programPtr); + auto context = reinterpret_cast(contextPtr); auto program = reinterpret_cast(programPtr); return GetImpl()->ProgramAst(context, program); } @@ -258,6 +280,25 @@ static KNativePointer impl_ProgramExternalSources(KNativePointer contextPtr, KNa } KOALA_INTEROP_2(ProgramExternalSources, KNativePointer, KNativePointer, KNativePointer); +static KNativePointer impl_ProgramDirectExternalSources(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto&& instance = reinterpret_cast(instancePtr); + std::size_t source_len = 0; + auto external_sources = GetImpl()->ProgramDirectExternalSources(context, instance, &source_len); + return new std::vector(external_sources, external_sources + source_len); +} +KOALA_INTEROP_2(ProgramDirectExternalSources, KNativePointer, KNativePointer, KNativePointer); + +static KNativePointer impl_ProgramModuleNameConst(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto program = reinterpret_cast(instancePtr); + auto result = GetImpl()->ProgramModuleNameConst(context, program); + return new std::string(result); +} +KOALA_INTEROP_2(ProgramModuleNameConst, KNativePointer, KNativePointer, KNativePointer); + static KNativePointer impl_ExternalSourceName(KNativePointer instance) { auto&& _instance_ = reinterpret_cast(instance); @@ -380,6 +421,14 @@ KNativePointer impl_ProgramFileNameWithExtensionConst(KNativePointer contextPtr, } KOALA_INTEROP_2(ProgramFileNameWithExtensionConst, KNativePointer, KNativePointer, KNativePointer) +KBoolean impl_ProgramIsASTLoweredConst(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto context = reinterpret_cast(contextPtr); + auto &&instance = reinterpret_cast(instancePtr); + return GetImpl()->ProgramIsASTLoweredConst(context, instance); +} +KOALA_INTEROP_2(ProgramIsASTLoweredConst, KBoolean, KNativePointer, KNativePointer); + KNativePointer impl_ETSParserGetGlobalProgramAbsName(KNativePointer contextPtr) { auto context = reinterpret_cast(contextPtr); @@ -488,3 +537,68 @@ KBoolean impl_IsArrayExpression(KNativePointer nodePtr) return GetImpl()->IsArrayExpression(node); } KOALA_INTEROP_1(IsArrayExpression, KBoolean, KNativePointer) + +void impl_MemInitialize() +{ + GetImpl()->MemInitialize(); +} +KOALA_INTEROP_V0(MemInitialize) + +void impl_MemFinalize() +{ + GetImpl()->MemFinalize(); +} +KOALA_INTEROP_V0(MemFinalize) + +inline KUInt unpackUInt(const KByte* bytes) { + const KUInt BYTE_0 = 0; + const KUInt BYTE_1 = 1; + const KUInt BYTE_2 = 2; + const KUInt BYTE_3 = 3; + + const KUInt BYTE_1_SHIFT = 8; + const KUInt BYTE_2_SHIFT = 16; + const KUInt BYTE_3_SHIFT = 24; + return ( + bytes[BYTE_0] + | (bytes[BYTE_1] << BYTE_1_SHIFT) + | (bytes[BYTE_2] << BYTE_2_SHIFT) + | (bytes[BYTE_3] << BYTE_3_SHIFT) + ); +} + +KNativePointer impl_CreateGlobalContext(KNativePointer configPtr, KStringArray externalFileListPtr, KInt fileNum, KBoolean lspUsage) +{ + auto config = reinterpret_cast(configPtr); + + const std::size_t headerLen = 4; + + const char** externalFileList = new const char*[fileNum]; + std::size_t position = headerLen; + std::size_t strLen; + for (std::size_t i = 0; i < static_cast(fileNum); ++i) { + strLen = unpackUInt(externalFileListPtr + position); + position += headerLen; + externalFileList[i] = strdup(std::string(reinterpret_cast(externalFileListPtr + position), strLen).c_str()); + position += strLen; + } + + return GetImpl()->CreateGlobalContext(config, externalFileList, fileNum, lspUsage); +} +KOALA_INTEROP_4(CreateGlobalContext, KNativePointer, KNativePointer, KStringArray, KInt, KBoolean) + +void impl_DestroyGlobalContext(KNativePointer globalContextPtr) +{ + auto context = reinterpret_cast(globalContextPtr); + GetImpl()->DestroyGlobalContext(context); +} +KOALA_INTEROP_V1(DestroyGlobalContext, KNativePointer) + +KNativePointer impl_CreateCacheContextFromFile(KNativePointer configPtr, KStringPtr& fileName, + KNativePointer globalContext, KBoolean isExternal) +{ + auto config = reinterpret_cast(configPtr); + auto context = reinterpret_cast(globalContext); + return GetImpl()->CreateCacheContextFromFile(config, getStringCopy(fileName), context, isExternal); +} +KOALA_INTEROP_4(CreateCacheContextFromFile, KNativePointer, KNativePointer, KStringPtr, KNativePointer, KBoolean) diff --git a/koala-wrapper/native/src/common.cc b/koala-wrapper/native/src/common.cc index eb7a6acb5..c191814e1 100644 --- a/koala-wrapper/native/src/common.cc +++ b/koala-wrapper/native/src/common.cc @@ -170,8 +170,20 @@ TODO: NOT FROM API (shouldn't be there) ----------------------------------------------------------------------------------------------------------------------------- */ -es2panda_AstNode * cachedParentNode; -es2panda_Context * cachedContext; +KNativePointer impl_AstNodeProgram(KNativePointer contextPtr, KNativePointer instancePtr) +{ + auto _context = reinterpret_cast(contextPtr); + auto _receiver = reinterpret_cast(instancePtr); + + if (GetImpl()->AstNodeIsProgramConst(_context, _receiver)) { + return GetImpl()->ETSModuleProgram(_context, _receiver); + } + return impl_AstNodeProgram(_context, GetImpl()->AstNodeParent(_context, _receiver)); +} +KOALA_INTEROP_2(AstNodeProgram, KNativePointer, KNativePointer, KNativePointer) + +thread_local es2panda_AstNode * cachedParentNode; +thread_local es2panda_Context * cachedContext; static void changeParent(es2panda_AstNode *child) { @@ -206,7 +218,7 @@ KNativePointer impl_AstNodeUpdateChildren(KNativePointer contextPtr, KNativePoin } KOALA_INTEROP_2(AstNodeUpdateChildren, KNativePointer, KNativePointer, KNativePointer) -std::vector cachedChildren; +thread_local std::vector cachedChildren; static void visitChild(es2panda_AstNode *node) { cachedChildren.emplace_back(node); diff --git a/koala-wrapper/native/src/generated/bridges.cc b/koala-wrapper/native/src/generated/bridges.cc index e1de4b1a1..d89b383f9 100644 --- a/koala-wrapper/native/src/generated/bridges.cc +++ b/koala-wrapper/native/src/generated/bridges.cc @@ -2707,16 +2707,6 @@ void impl_TSTypeAliasDeclarationSetTypeParameters(KNativePointer context, KNativ } KOALA_INTEROP_V3(TSTypeAliasDeclarationSetTypeParameters, KNativePointer, KNativePointer, KNativePointer); -KNativePointer impl_TSTypeAliasDeclarationAnnotations(KNativePointer context, KNativePointer receiver) -{ - const auto _context = reinterpret_cast(context); - const auto _receiver = reinterpret_cast(receiver); - std::size_t length; - auto result = GetImpl()->TSTypeAliasDeclarationAnnotations(_context, _receiver, &length); - return new std::vector(result, result + length); -} -KOALA_INTEROP_2(TSTypeAliasDeclarationAnnotations, KNativePointer, KNativePointer, KNativePointer); - KNativePointer impl_TSTypeAliasDeclarationAnnotationsConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); @@ -3325,16 +3315,6 @@ void impl_ScriptFunctionAddFlag(KNativePointer context, KNativePointer receiver, } KOALA_INTEROP_V3(ScriptFunctionAddFlag, KNativePointer, KNativePointer, KInt); -void impl_ScriptFunctionAddModifier(KNativePointer context, KNativePointer receiver, KInt flags) -{ - const auto _context = reinterpret_cast(context); - const auto _receiver = reinterpret_cast(receiver); - const auto _flags = static_cast(flags); - GetImpl()->ScriptFunctionAddModifier(_context, _receiver, _flags); - return ; -} -KOALA_INTEROP_V3(ScriptFunctionAddModifier, KNativePointer, KNativePointer, KInt); - KUInt impl_ScriptFunctionFormalParamsLengthConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); @@ -4681,6 +4661,58 @@ void impl_ETSTupleSetTypeAnnotationsList(KNativePointer context, KNativePointer } KOALA_INTEROP_V4(ETSTupleSetTypeAnnotationsList, KNativePointer, KNativePointer, KNativePointerArray, KUInt); +KNativePointer impl_CreateTryStatement(KNativePointer context, KNativePointer block, KNativePointerArray catchClauses, KUInt catchClausesSequenceLength, KNativePointer finalizer, KNativePointerArray finalizerInsertionsLabelPair, KUInt finalizerInsertionsLabelPairSequenceLength, KNativePointerArray finalizerInsertionsStatement, KUInt finalizerInsertionsStatementSequenceLength) +{ + const auto _context = reinterpret_cast(context); + const auto _block = reinterpret_cast(block); + const auto _catchClauses = reinterpret_cast(catchClauses); + const auto _catchClausesSequenceLength = static_cast(catchClausesSequenceLength); + const auto _finalizer = reinterpret_cast(finalizer); + const auto _finalizerInsertionsLabelPair = reinterpret_cast(finalizerInsertionsLabelPair); + const auto _finalizerInsertionsLabelPairSequenceLength = static_cast(finalizerInsertionsLabelPairSequenceLength); + const auto _finalizerInsertionsStatement = reinterpret_cast(finalizerInsertionsStatement); + const auto _finalizerInsertionsStatementSequenceLength = static_cast(finalizerInsertionsStatementSequenceLength); + auto result = GetImpl()->CreateTryStatement(_context, _block, _catchClauses, _catchClausesSequenceLength, _finalizer, _finalizerInsertionsLabelPair, _finalizerInsertionsLabelPairSequenceLength, _finalizerInsertionsStatement, _finalizerInsertionsStatementSequenceLength); + return result; +} +KOALA_INTEROP_9(CreateTryStatement, KNativePointer, KNativePointer, KNativePointer, KNativePointerArray, KUInt, KNativePointer, KNativePointerArray, KUInt, KNativePointerArray, KUInt); + +KNativePointer impl_UpdateTryStatement(KNativePointer context, KNativePointer original, KNativePointer block, KNativePointerArray catchClauses, KUInt catchClausesSequenceLength, KNativePointer finalizer, KNativePointerArray finalizerInsertionsLabelPair, KUInt finalizerInsertionsLabelPairSequenceLength, KNativePointerArray finalizerInsertionsStatement, KUInt finalizerInsertionsStatementSequenceLength) +{ + const auto _context = reinterpret_cast(context); + const auto _original = reinterpret_cast(original); + const auto _block = reinterpret_cast(block); + const auto _catchClauses = reinterpret_cast(catchClauses); + const auto _catchClausesSequenceLength = static_cast(catchClausesSequenceLength); + const auto _finalizer = reinterpret_cast(finalizer); + const auto _finalizerInsertionsLabelPair = reinterpret_cast(finalizerInsertionsLabelPair); + const auto _finalizerInsertionsLabelPairSequenceLength = static_cast(finalizerInsertionsLabelPairSequenceLength); + const auto _finalizerInsertionsStatement = reinterpret_cast(finalizerInsertionsStatement); + const auto _finalizerInsertionsStatementSequenceLength = static_cast(finalizerInsertionsStatementSequenceLength); + auto result = GetImpl()->UpdateTryStatement(_context, _original, _block, _catchClauses, _catchClausesSequenceLength, _finalizer, _finalizerInsertionsLabelPair, _finalizerInsertionsLabelPairSequenceLength, _finalizerInsertionsStatement, _finalizerInsertionsStatementSequenceLength); + return result; +} +KOALA_INTEROP_10(UpdateTryStatement, KNativePointer, KNativePointer, KNativePointer, KNativePointer, KNativePointerArray, KUInt, KNativePointer, KNativePointerArray, KUInt, KNativePointerArray, KUInt); + +KNativePointer impl_CreateTryStatement1(KNativePointer context, KNativePointer other) +{ + const auto _context = reinterpret_cast(context); + const auto _other = reinterpret_cast(other); + auto result = GetImpl()->CreateTryStatement1(_context, _other); + return result; +} +KOALA_INTEROP_2(CreateTryStatement1, KNativePointer, KNativePointer, KNativePointer); + +KNativePointer impl_UpdateTryStatement1(KNativePointer context, KNativePointer original, KNativePointer other) +{ + const auto _context = reinterpret_cast(context); + const auto _original = reinterpret_cast(original); + const auto _other = reinterpret_cast(other); + auto result = GetImpl()->UpdateTryStatement1(_context, _original, _other); + return result; +} +KOALA_INTEROP_3(UpdateTryStatement1, KNativePointer, KNativePointer, KNativePointer, KNativePointer); + KNativePointer impl_TryStatementFinallyBlockConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); @@ -6639,16 +6671,6 @@ KNativePointer impl_ImportDeclarationSpecifiersConst(KNativePointer context, KNa } KOALA_INTEROP_2(ImportDeclarationSpecifiersConst, KNativePointer, KNativePointer, KNativePointer); -KNativePointer impl_ImportDeclarationSpecifiers(KNativePointer context, KNativePointer receiver) -{ - const auto _context = reinterpret_cast(context); - const auto _receiver = reinterpret_cast(receiver); - std::size_t length; - auto result = GetImpl()->ImportDeclarationSpecifiers(_context, _receiver, &length); - return new std::vector(result, result + length); -} -KOALA_INTEROP_2(ImportDeclarationSpecifiers, KNativePointer, KNativePointer, KNativePointer); - KBoolean impl_ImportDeclarationIsTypeKindConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); @@ -6735,15 +6757,6 @@ KNativePointer impl_UpdateETSImportDeclaration(KNativePointer context, KNativePo } KOALA_INTEROP_6(UpdateETSImportDeclaration, KNativePointer, KNativePointer, KNativePointer, KNativePointer, KNativePointerArray, KUInt, KInt); -KNativePointer impl_ETSImportDeclarationAssemblerName(KNativePointer context, KNativePointer receiver) -{ - const auto _context = reinterpret_cast(context); - const auto _receiver = reinterpret_cast(receiver); - auto result = GetImpl()->ETSImportDeclarationAssemblerName(_context, _receiver); - return new std::string(result); -} -KOALA_INTEROP_2(ETSImportDeclarationAssemblerName, KNativePointer, KNativePointer, KNativePointer); - KNativePointer impl_ETSImportDeclarationAssemblerNameConst(KNativePointer context, KNativePointer receiver) { const auto _context = reinterpret_cast(context); diff --git a/koala-wrapper/src/Es2pandaNativeModule.ts b/koala-wrapper/src/Es2pandaNativeModule.ts index 78314c0cc..0c8bfb0a0 100644 --- a/koala-wrapper/src/Es2pandaNativeModule.ts +++ b/koala-wrapper/src/Es2pandaNativeModule.ts @@ -21,6 +21,7 @@ import { registerNativeModuleLibraryName, loadNativeModuleLibrary, KDouble, + KStringArrayPtr, } from '@koalaui/interop'; import { Es2pandaNativeModule as GeneratedEs2pandaNativeModule } from './generated/Es2pandaNativeModule'; import * as path from 'path'; @@ -734,7 +735,12 @@ export class Es2pandaNativeModule { _ProgramExternalSources(context: KNativePointer, instance: KNativePointer): KNativePointer { throw new Error('Not implemented'); } - + _ProgramDirectExternalSources(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } + _AstNodeProgram(context: KNativePointer, instance: KNativePointer): KNativePointer { + throw new Error('Not implemented'); + } _ExternalSourceName(instance: KNativePointer): KNativePointer { throw new Error('Not implemented'); } @@ -793,6 +799,10 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } + _ProgramIsASTLoweredConst(context: KPtr, program: KPtr): KBoolean { + throw new Error('Not implemented'); + } + _ETSParserGetGlobalProgramAbsName(context: KNativePointer): KNativePointer { throw new Error('Not implemented'); } @@ -825,6 +835,10 @@ export class Es2pandaNativeModule { throw new Error('Not implemented'); } + _ProgramModuleNameConst(context: KPtr, program: KPtr): KNativePointer { + throw new Error('Not implemented'); + } + _AstNodeRangeConst(context: KNativePointer, node: KNativePointer): KNativePointer { throw new Error('CreateFunctionDecl was not overloaded by native module initialization'); } @@ -842,7 +856,37 @@ export class Es2pandaNativeModule { } _IsArrayExpression(node: KPtr): KBoolean { - throw new Error('Not implemented'); + throw new Error('IsArrayExpression was not overloaded by native module initialization'); + } + + _MemInitialize(): void { + throw new Error('MemInitialize was not overloaded by native module initialization'); + } + + _MemFinalize(): void { + throw new Error('MemFinalize was not overloaded by native module initialization'); + } + + _CreateGlobalContext(configPtr: KNativePointer, externalFileList: KStringArrayPtr, fileNum: KInt, + lspUsage: boolean): KNativePointer { + throw new Error('CreateGlobalContext was not overloaded by native module initialization'); + } + + _DestroyGlobalContext(contextPtr: KNativePointer): void { + throw new Error('DestroyGlobalContext was not overloaded by native module initialization'); + } + + _CreateCacheContextFromFile(configPtr: KNativePointer, filename: string, globalContext: KNativePointer, + isExternal: KBoolean): KNativePointer { + throw new Error('CreateCacheContextFromFile was not overloaded by native module initialization'); + } + + _InsertGlobalStructInfo(context: KNativePointer, str: String): void { + throw new Error('InsertGlobalStructInfo was not overloaded by native module initialization'); + } + + _HasGlobalStructInfo(context: KNativePointer, str: String): KBoolean { + throw new Error('HasGlobalStructInfo was not overloaded by native module initialization'); } } diff --git a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts index 536c1ef3f..2dc5361a0 100644 --- a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts +++ b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts @@ -74,7 +74,9 @@ import { ObjectExpression, Property, TemplateLiteral, - ArrayExpression + ArrayExpression, + AnnotationDeclaration, + TryStatement } from "../../generated" import { Es2pandaModifierFlags @@ -135,6 +137,8 @@ import { updateObjectExpression } from "../node-utilities/ObjectExpression" import { updateProperty } from "../node-utilities/Property" import { updateTemplateLiteral } from "../node-utilities/TemplateLiteral" import { updateArrayExpression } from "../node-utilities/ArrayExpression"; +import { updateAnnotationDeclaration } from "../node-utilities/AnnotationDeclaration" +import { updateTryStatement } from "../node-utilities/TryStatement" export const factory = { get createIdentifier() { @@ -365,6 +369,12 @@ export const factory = { get updateUndefinedLiteral() { return updateUndefinedLiteral }, + get createAnnotationDeclaration() { + return AnnotationDeclaration.create1AnnotationDeclaration + }, + get updateAnnotationDeclaration() { + return updateAnnotationDeclaration + }, get createAnnotationUsage() { return AnnotationUsage.createAnnotationUsage }, @@ -476,6 +486,12 @@ export const factory = { get updateArrayExpression(): (...args: Parameters) => ArrayExpression { return updateArrayExpression; }, + get createTryStatement(): (...args: Parameters) => TryStatement { + return TryStatement.createTryStatement; + }, + get updateTryStatement(): (...args: Parameters) => TryStatement { + return updateTryStatement; + }, /** @deprecated */ createTypeParameter1_(name: Identifier, constraint?: TypeNode, defaultType?: TypeNode) { return TSTypeParameter.createTSTypeParameter(Identifier.create1Identifier(name.name), constraint, defaultType) diff --git a/koala-wrapper/src/arkts-api/index.ts b/koala-wrapper/src/arkts-api/index.ts index a77ec8acd..b177455ad 100644 --- a/koala-wrapper/src/arkts-api/index.ts +++ b/koala-wrapper/src/arkts-api/index.ts @@ -15,6 +15,7 @@ export * from "../Es2pandaEnums" export * from "../generated/Es2pandaEnums" +export * from "../generated/peers/AnnotationDeclaration" export * from "../generated/peers/AnnotationUsage" export * from "../generated/peers/BlockStatement" export * from "../generated/peers/ETSPrimitiveType" @@ -59,7 +60,8 @@ export * from "../generated/peers/BlockExpression" export * from "../generated/peers/TSClassImplements" export * from "../generated/peers/BooleanLiteral" export * from "../generated/peers/TSArrayType" -export * from "../generated/peers/ArrayExpression"; +export * from "../generated/peers/ArrayExpression" +export * from "../generated/peers/TryStatement" export * from "./types" export * from "./utilities/private" @@ -79,4 +81,4 @@ export * from "./peers/SourcePosition" export * from "./peers/SourceRange" export * from "./to-be-generated/MemberExpression" export * from "./static/globalUtils" -export { global as arktsGlobal } from "./static/global"; +export { global as arktsGlobal } from "./static/global" diff --git a/arkui-plugins/test/local/@ohos.arkui.component.column.d.ets b/koala-wrapper/src/arkts-api/node-utilities/AnnotationDeclaration.ts similarity index 39% rename from arkui-plugins/test/local/@ohos.arkui.component.column.d.ets rename to koala-wrapper/src/arkts-api/node-utilities/AnnotationDeclaration.ts index 915dc5ceb..345d95f21 100644 --- a/arkui-plugins/test/local/@ohos.arkui.component.column.d.ets +++ b/koala-wrapper/src/arkts-api/node-utilities/AnnotationDeclaration.ts @@ -1,10 +1,10 @@ /* - * Copyright (C) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,29 +13,20 @@ * limitations under the License. */ -import { memo } from '../stateManagement/runtime'; -import { ComponentBuilder, CommonMethod, PointLightStyle } from './common'; -import { HorizontalAlign, FlexAlign } from './enums'; +import { AnnotationDeclaration, Expression } from '../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { attachModifiers, updateThenAttach } from '../utilities/private'; +import { AstNode } from '../peers/AstNode'; -export declare interface ColumnOptions { - space?: string | number; -} +export function updateAnnotationDeclaration( + original: AnnotationDeclaration, + expr: Expression | undefined, + properties: readonly AstNode[] +): AnnotationDeclaration { + if (isSameNativeObject(expr, original.expr) && isSameNativeObject(properties, original.properties)) { + return original; + } -export declare interface ColumnAttribute extends CommonMethod { - @memo - alignItems(value: HorizontalAlign): this; - @memo - justifyContent(value: FlexAlign): this; - @memo - pointLight(value: PointLightStyle): this; - @memo - reverse(isReversed?: boolean): this; + const update = updateThenAttach(AnnotationDeclaration.update1AnnotationDeclaration, attachModifiers); + return update(original, expr, properties); } - -@memo -@ComponentBuilder -export declare function Column ( - options?: ColumnOptions, - @memo - content?: () => void -): ColumnAttribute; \ No newline at end of file diff --git a/koala-wrapper/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts b/koala-wrapper/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts index d268c5d82..1d607b245 100644 --- a/koala-wrapper/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts +++ b/koala-wrapper/src/arkts-api/node-utilities/TSInterfaceDeclaration.ts @@ -38,6 +38,10 @@ export function updateTSInterfaceDeclaration( return original; } - const update = updateThenAttach(TSInterfaceDeclaration.updateTSInterfaceDeclaration, attachModifiers); + const update = updateThenAttach( + TSInterfaceDeclaration.updateTSInterfaceDeclaration, + attachModifiers, + (node: TSInterfaceDeclaration, original: TSInterfaceDeclaration) => node.setAnnotations(original.annotations) + ); return update(original, _extends, id, typeParams, body, isStatic, isExternal); } diff --git a/koala-wrapper/src/arkts-api/node-utilities/TryStatement.ts b/koala-wrapper/src/arkts-api/node-utilities/TryStatement.ts new file mode 100644 index 000000000..32512066c --- /dev/null +++ b/koala-wrapper/src/arkts-api/node-utilities/TryStatement.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LabelPair } from '../../generated/peers/LabelPair'; +import { BlockStatement, CatchClause, Statement, TryStatement } from '../../generated'; +import { isSameNativeObject } from '../peers/ArktsObject'; +import { attachModifiers, updateThenAttach } from '../utilities/private'; + +export function updateTryStatement( + original: TryStatement, + block: BlockStatement | undefined, + catchClauses: readonly CatchClause[], + finalizer: BlockStatement | undefined, + finalizerInsertionsLabelPair: readonly LabelPair[], + finalizerInsertionsStatement: readonly Statement[] +): TryStatement { + if ( + isSameNativeObject(block, original.block) && + isSameNativeObject(catchClauses, original.catchClauses) && + isSameNativeObject(finalizer, original.finallyBlock) + /* TODO: no getter for finalizerInsertionsLabelPair */ + /* TODO: no getter for finalizerInsertionsStatement */ + ) { + return original; + } + + const update = updateThenAttach(TryStatement.updateTryStatement, attachModifiers); + return update(original, block, catchClauses, finalizer, finalizerInsertionsLabelPair, finalizerInsertionsStatement); +} diff --git a/koala-wrapper/src/arkts-api/peers/AstNode.ts b/koala-wrapper/src/arkts-api/peers/AstNode.ts index 62a0b78d2..e60cd5c06 100644 --- a/koala-wrapper/src/arkts-api/peers/AstNode.ts +++ b/koala-wrapper/src/arkts-api/peers/AstNode.ts @@ -13,122 +13,125 @@ * limitations under the License. */ -import { isNullPtr, KInt, KNativePointer as KPtr, KNativePointer, nullptr } from "@koalaui/interop" -import { global } from "../static/global" -import { allFlags, nodeType, unpackNodeArray, unpackNonNullableNode, unpackString } from "../utilities/private" -import { throwError } from "../../utils" -import { Es2pandaModifierFlags } from "../../generated/Es2pandaEnums" -import { ArktsObject } from "./ArktsObject" -import { Es2pandaAstNodeType } from "../../Es2pandaEnums" +import { isNullPtr, KInt, KNativePointer as KPtr, KNativePointer, nullptr } from '@koalaui/interop'; +import { global } from '../static/global'; +import { allFlags, nodeType, unpackNode, unpackNodeArray, unpackNonNullableNode, unpackString } from '../utilities/private'; +import { throwError } from '../../utils'; +import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; +import { ArktsObject } from './ArktsObject'; +import { Es2pandaAstNodeType } from '../../Es2pandaEnums'; export abstract class AstNode extends ArktsObject { protected constructor(peer: KNativePointer) { if (isNullPtr(peer)) { - throwError(`attempted to create AstNode from nullptr`) + throwError(`attempted to create AstNode from nullptr`); } - super(peer) - this.updateChildren() + super(peer); + this.updateChildren(); } public get originalPeer(): KNativePointer { - const result = global.generatedEs2panda._AstNodeOriginalNodeConst(global.context, this.peer) + const result = global.generatedEs2panda._AstNodeOriginalNodeConst(global.context, this.peer); if (result === nullptr) { - this.originalPeer = this.peer - return this.peer + this.originalPeer = this.peer; + return this.peer; } - return result + return result; } public set originalPeer(peer: KNativePointer) { - global.generatedEs2panda._AstNodeSetOriginalNode(global.context, this.peer, peer) + global.generatedEs2panda._AstNodeSetOriginalNode(global.context, this.peer, peer); } public getChildren(): readonly AstNode[] { - return unpackNodeArray(global.es2panda._AstNodeChildren(global.context, this.peer)) + return unpackNodeArray(global.es2panda._AstNodeChildren(global.context, this.peer)); } public getSubtree(): readonly AstNode[] { return this.getChildren().reduce( (prev: readonly AstNode[], curr) => { - return prev.concat(curr.getSubtree()) + return prev.concat(curr.getSubtree()); }, [this] - ) + ); } public updateChildren(): void { if (this.peer === nullptr) { - throwError('updateChildren called on NULLPTR') + throwError('updateChildren called on NULLPTR'); } - global.es2panda._AstNodeUpdateChildren(global.context, this.peer) + global.es2panda._AstNodeUpdateChildren(global.context, this.peer); } public updateModifiers(modifierFlags: KInt | undefined): this { - global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags) - global.generatedEs2panda._AstNodeAddModifier(global.context, this.peer, modifierFlags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE) - return this + global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags); + global.generatedEs2panda._AstNodeAddModifier( + global.context, + this.peer, + modifierFlags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ); + return this; } public dump(indentation: number = 0): string { - const children = this.getChildren() - .map((it) => it.dump(indentation + 1)) - const msg = - `${indentation}_` - + ` ` - + this.dumpMessage() - return "> " + " ".repeat(4 * indentation) + msg + "\n" + children.join("") + const children = this.getChildren().map((it) => it.dump(indentation + 1)); + const msg = `${indentation}_` + ` ` + this.dumpMessage(); + return '> ' + ' '.repeat(4 * indentation) + msg + '\n' + children.join(''); } protected dumpMessage(): string { - return `` + return ``; } public dumpJson(): string { - return unpackString(global.generatedEs2panda._AstNodeDumpJSONConst(global.context, this.peer)) + return unpackString(global.generatedEs2panda._AstNodeDumpJSONConst(global.context, this.peer)); } public dumpSrc(): string { - return unpackString(global.generatedEs2panda._AstNodeDumpEtsSrcConst(global.context, this.peer)) + return unpackString(global.generatedEs2panda._AstNodeDumpEtsSrcConst(global.context, this.peer)); } public dumpModifiers(): string { - return unpackString(global.es2panda._AstNodeDumpModifiers(global.context, this.peer)) + return unpackString(global.es2panda._AstNodeDumpModifiers(global.context, this.peer)); } public clone(): this { - return unpackNonNullableNode(global.generatedEs2panda._AstNodeClone(global.context, this.peer, this.parent.peer)); + const clonedNode = unpackNonNullableNode( + global.generatedEs2panda._AstNodeClone(global.context, this.peer, this.parent?.peer ?? nullptr) + ); + clonedNode.parent = undefined; + return clonedNode as this; } - public get parent(): AstNode { - const parent = global.generatedEs2panda._AstNodeParent(global.context, this.peer) - if (parent === nullptr) { - throwError(`no parent`) - } - return unpackNonNullableNode(parent) + public get parent(): AstNode | undefined { + const parent = global.generatedEs2panda._AstNodeParent(global.context, this.peer); + return unpackNode(parent); } - public set parent(node: AstNode) { - global.generatedEs2panda._AstNodeSetParent(global.context, this.peer, node.peer) + public set parent(node: AstNode | undefined) { + global.generatedEs2panda._AstNodeSetParent(global.context, this.peer, node?.peer ?? nullptr); } public get modifiers(): KInt { - return global.generatedEs2panda._AstNodeModifiers(global.context, this.peer) + return global.generatedEs2panda._AstNodeModifiers(global.context, this.peer); } public set modifiers(flags: KInt | undefined) { - global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags) - global.generatedEs2panda._AstNodeAddModifier(global.context, this.peer, flags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE) + global.generatedEs2panda._AstNodeClearModifier(global.context, this.peer, allFlags); + global.generatedEs2panda._AstNodeAddModifier( + global.context, + this.peer, + flags ?? Es2pandaModifierFlags.MODIFIER_FLAGS_NONE + ); } public get isStatic(): boolean { - return global.generatedEs2panda._AstNodeIsStaticConst(global.context, this.peer) + return global.generatedEs2panda._AstNodeIsStaticConst(global.context, this.peer); } } - export class UnsupportedNode extends AstNode { constructor(peer: KPtr) { - super(peer) - + super(peer); } } diff --git a/koala-wrapper/src/arkts-api/peers/Context.ts b/koala-wrapper/src/arkts-api/peers/Context.ts index 81a1ec31f..b4bf7a203 100644 --- a/koala-wrapper/src/arkts-api/peers/Context.ts +++ b/koala-wrapper/src/arkts-api/peers/Context.ts @@ -13,39 +13,43 @@ * limitations under the License. */ -import { ArktsObject } from "./ArktsObject" -import { global } from "../static/global" -import { throwError, filterSource } from "../../utils" -import { passString } from "../utilities/private" -import { KNativePointer } from "@koalaui/interop" -import { AstNode } from "./AstNode" -import { Program } from "./Program" +import { ArktsObject } from './ArktsObject'; +import { global } from '../static/global'; +import { throwError, filterSource } from '../../utils'; +import { passString } from '../utilities/private'; +import { KBoolean, KNativePointer } from '@koalaui/interop'; +import { AstNode } from './AstNode'; +import { Program } from './Program'; export class Context extends ArktsObject { constructor(peer: KNativePointer) { - super(peer) + super(peer); } - static createFromString( - source: string - ): Context { + static createFromString(source: string): Context { if (!global.configIsInitialized()) { - throwError(`Config not initialized`) + throwError(`Config not initialized`); } return new Context( - global.es2panda._CreateContextFromString( - global.config, - passString(source), - passString(global.filePath) - ) - ) + global.es2panda._CreateContextFromString(global.config, passString(source), passString(global.filePath)) + ); } - static destroyAndRecreate( - ast: AstNode + + static createCacheContextFromFile( + configPtr: KNativePointer, + fileName: string, + globalContextPtr: KNativePointer, + isExternal: KBoolean ): Context { - console.log("[TS WRAPPER] DESTROY AND RECREATE"); - const source = filterSource(ast.dumpSrc()) - global.es2panda._DestroyContext(global.context) - global.compilerContext = Context.createFromString(source) + return new Context( + global.es2panda._CreateCacheContextFromFile(configPtr, passString(fileName), globalContextPtr, isExternal) + ); + } + + static destroyAndRecreate(ast: AstNode): Context { + console.log('[TS WRAPPER] DESTROY AND RECREATE'); + const source = filterSource(ast.dumpSrc()); + global.es2panda._DestroyContext(global.context); + global.compilerContext = Context.createFromString(source); return new Context(global.context); } @@ -53,4 +57,4 @@ export class Context extends ArktsObject { get program(): Program { return new Program(global.es2panda._ContextProgram(this.peer)); } -} \ No newline at end of file +} diff --git a/koala-wrapper/src/arkts-api/peers/Program.ts b/koala-wrapper/src/arkts-api/peers/Program.ts index 5f3afbed2..5734dc4a4 100644 --- a/koala-wrapper/src/arkts-api/peers/Program.ts +++ b/koala-wrapper/src/arkts-api/peers/Program.ts @@ -35,17 +35,32 @@ export class Program extends ArktsObject { ); } - get programFileName(): string { + get directExternalSources(): ExternalSource[] { + return acceptNativeObjectArrayResult( + global.es2panda._ProgramDirectExternalSources(global.context, this.peer), + (instance: KNativePointer) => new ExternalSource(instance) + ); + } + + get fileName(): string { return unpackString(global.es2panda._ProgramFileNameConst(global.context, this.peer)); } - get programFileNameWithExtension(): string { + get fileNameWithExtension(): string { return unpackString(global.es2panda._ProgramFileNameWithExtensionConst(global.context, this.peer)); } - get programGlobalAbsName(): string { + get globalAbsName(): string { return unpackString(global.es2panda._ETSParserGetGlobalProgramAbsName(global.context)); } + + get moduleName(): string { + return unpackString(global.es2panda._ProgramModuleNameConst(global.context, this.peer)); + } + + isASTLowered(): boolean { + return global.es2panda._ProgramIsASTLoweredConst(global.context, this.peer); + } } export class ExternalSource extends ArktsObject { diff --git a/koala-wrapper/src/arkts-api/types.ts b/koala-wrapper/src/arkts-api/types.ts index 7e97b8a7c..8e9f24092 100644 --- a/koala-wrapper/src/arkts-api/types.ts +++ b/koala-wrapper/src/arkts-api/types.ts @@ -90,7 +90,7 @@ export class EtsScript extends AstNode { global.config = Config.createDefault().peer; } global.compilerContext = Context.createFromString(source); - proceedToState(state); + proceedToState(state, global.context); return new EtsScript( global.es2panda._ProgramAst(global.context, global.es2panda._ContextProgram(global.context)) ); diff --git a/koala-wrapper/src/arkts-api/utilities/performance.ts b/koala-wrapper/src/arkts-api/utilities/performance.ts index bafe9df5d..0c440b88a 100644 --- a/koala-wrapper/src/arkts-api/utilities/performance.ts +++ b/koala-wrapper/src/arkts-api/utilities/performance.ts @@ -34,15 +34,22 @@ function pad(value: number, length: number): string { return value.toString().padStart(length, '0'); } +function round(value: number, index: number=2): number { + const factor = Math.pow(10, index); + return Math.round(value * factor) / factor; +} + export class Performance { private static instance: Performance; private events: Map; + private historyEvents = new Map(); private scopes: string[]; private shouldSkip: boolean; private totalDuration: number; private constructor() { this.events = new Map(); + this.historyEvents = new Map(); this.scopes = []; this.shouldSkip = true; this.totalDuration = 0; @@ -82,15 +89,18 @@ export class Performance { const endTime: number = performance.now(); const parentEvent: string = this.scopes[this.scopes.length - 1]; const duration: number = endTime - event.startTime; - this.totalDuration += duration; + this.totalDuration += !parentEvent ? duration : 0; if (shouldLog) { console.log( - `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}, total: ${formatTime(this.totalDuration)}` + `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}(${round(duration)}), total: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})` ); } - return { ...event, endTime, parentEvent, duration }; + const newEvent = { ...event, endTime, parentEvent, duration }; + const history = this.historyEvents.get(parentEvent ?? null) || []; + this.historyEvents.set(parentEvent ?? null, [...history, newEvent]); + return newEvent; } stopLastEvent(shouldLog: boolean = false): Event { @@ -107,15 +117,18 @@ export class Performance { const endTime: number = performance.now(); const parentEvent: string = this.scopes[this.scopes.length - 1]; const duration: number = endTime - event.startTime; - this.totalDuration += duration; + this.totalDuration += !parentEvent ? duration : 0; if (shouldLog) { console.log( - `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}, total: ${formatTime(this.totalDuration)}` + `[PERFORMANCE] name: ${event.name}, parent: ${parentEvent}, duration: ${formatTime(duration)}(${round(duration)}), total: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})` ); } - return { ...event, endTime, parentEvent, duration }; + const newEvent = { ...event, endTime, parentEvent, duration }; + const history = this.historyEvents.get(parentEvent ?? null) || []; + this.historyEvents.set(parentEvent ?? null, [...history, newEvent]); + return newEvent; } clearAllEvents(shouldLog: boolean = false): void { @@ -129,4 +142,35 @@ export class Performance { clearTotalDuration(): void { this.totalDuration = 0; } + + clearHistory(): void { + this.historyEvents = new Map(); + } + + visualizeEvents(shouldLog: boolean = false): void { + if (this.shouldSkip) return; + const that = this; + function buildVisualization(parentKey: string | null, indentLevel: number): [string, number] { + const children = that.historyEvents.get(parentKey) || []; + let result = ''; + + children.forEach(child => { + const indent = ' '.repeat(indentLevel); + const duration = child.duration ?? 0; + const [_result, count] = buildVisualization(child.name, indentLevel + 1); + result += `${indent}- ${child.name}: ${formatTime(duration)}(${round(duration)}), ${count}\n`; + result += _result; + }); + + return [result, children.length]; + } + + const [finalResult, _] = buildVisualization(null, 0); + if (shouldLog) { + console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + console.log(`TOTAL: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})`); + console.log(finalResult.trimEnd()); + console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + } + } } \ No newline at end of file diff --git a/koala-wrapper/src/arkts-api/utilities/public.ts b/koala-wrapper/src/arkts-api/utilities/public.ts index 1ebdd1b26..a22803cf0 100644 --- a/koala-wrapper/src/arkts-api/utilities/public.ts +++ b/koala-wrapper/src/arkts-api/utilities/public.ts @@ -16,7 +16,7 @@ import { global } from '../static/global'; import { isNumber, throwError, getEnumName } from '../../utils'; import { KNativePointer, KInt, nullptr, withStringResult } from '@koalaui/interop'; -import { passNode, passString, unpackNodeArray, unpackNonNullableNode } from './private'; +import { passNode, passString, passStringArray, unpackNodeArray, unpackNonNullableNode } from './private'; import { isFunctionDeclaration, isMemberExpression, isMethodDefinition, isNumberLiteral } from '../factory/nodeTests'; import { Es2pandaContextState, @@ -43,34 +43,35 @@ import { clearNodeCache } from '../class-by-peer'; import { SourcePosition } from '../peers/SourcePosition'; import { MemberExpression } from '../to-be-generated/MemberExpression'; -export function proceedToState(state: Es2pandaContextState, forceDtsEmit = false): void { +export function proceedToState(state: Es2pandaContextState, context: KNativePointer, forceDtsEmit = false): void { console.log('[TS WRAPPER] PROCEED TO STATE: ', getEnumName(Es2pandaContextState, state)); - if (global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR) { - processErrorState(state, forceDtsEmit); + if (global.es2panda._ContextState(context) === Es2pandaContextState.ES2PANDA_STATE_ERROR) { + clearNodeCache(); + processErrorState(state, context, forceDtsEmit); } - if (state <= global.es2panda._ContextState(global.context)) { + if (state <= global.es2panda._ContextState(context)) { console.log('[TS WRAPPER] PROCEED TO STATE: SKIPPING'); return; } clearNodeCache(); - global.es2panda._ProceedToState(global.context, state); - processErrorState(state, forceDtsEmit); + global.es2panda._ProceedToState(context, state); + processErrorState(state, context, forceDtsEmit); } -function processErrorState(state: Es2pandaContextState, forceDtsEmit = false): void { +function processErrorState(state: Es2pandaContextState, context: KNativePointer, forceDtsEmit = false): void { try { if ( - global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR && + global.es2panda._ContextState(context) === Es2pandaContextState.ES2PANDA_STATE_ERROR && !forceDtsEmit ) { - const errorMessage = withStringResult(global.es2panda._ContextErrorMessage(global.context)); + const errorMessage = withStringResult(global.es2panda._ContextErrorMessage(context)); if (errorMessage === undefined) { throwError(`Could not get ContextErrorMessage`); } throwError([`Failed to proceed to ${Es2pandaContextState[state]}`, errorMessage].join(`\n`)); } } catch (e) { - global.es2panda._DestroyContext(global.context); + global.es2panda._DestroyContext(context); throw e; } } @@ -98,7 +99,7 @@ export function getDecl(node: AstNode): AstNode | undefined { if (!!decl) { return decl; } - if (isProperty(node.parent)) { + if (!!node.parent && isProperty(node.parent)) { return getDeclFromProperty(node.parent); } return undefined; @@ -108,7 +109,7 @@ function getDeclFromProperty(node: Property): AstNode | undefined { if (!node.key) { return undefined; } - if (!isObjectExpression(node.parent)) { + if (!!node.parent && !isObjectExpression(node.parent)) { return getPeerDecl(passNode(node.key)); } return getDeclFromObjectExpressionProperty(node); @@ -210,6 +211,10 @@ export function importDeclarationInsert(node: ETSImportDeclaration, program: Pro global.es2panda._InsertETSImportDeclarationAndParse(global.context, program.peer, node.peer); } +export function getProgramFromAstNode(node: AstNode): Program { + return new Program(global.es2panda._AstNodeProgram(global.context, node.peer)); +} + export function hasModifierFlag(node: AstNode, flag: Es2pandaModifierFlags): boolean { if (!node) return false; @@ -270,3 +275,32 @@ export function getStartPosition(node: AstNode): SourcePosition { export function getEndPosition(node: AstNode): SourcePosition { return new SourcePosition(global.es2panda._AstNodeEndConst(global.context, node.peer)); } + +export function MemInitialize() { + global.es2panda._MemInitialize(); +} + +export function MemFinalize() { + global.es2panda._MemFinalize(); +} + +export function CreateGlobalContext(config: KNativePointer, externalFileList: string[], fileNum: KInt, lspUsage: boolean): KNativePointer { + return global.es2panda._CreateGlobalContext(config, passStringArray(externalFileList), fileNum, lspUsage); +} + +export function DestroyGlobalContext(context: KNativePointer): void { + global.es2panda._DestroyGlobalContext(context); +} + +export function CreateCacheContextFromFile(configPtr: KNativePointer, filename: string, globalContext: KNativePointer, + isExternal: Boolean): KNativePointer { + return global.es2panda._CreateCacheContextFromFile(configPtr, passString(filename), globalContext, isExternal); +} + +export function insertGlobalStructInfo(structName: string): void { + global.es2panda._InsertGlobalStructInfo(global.context, passString(structName)); +} + +export function hasGlobalStructInfo(structName: string): boolean { + return global.es2panda._HasGlobalStructInfo(global.context, passString(structName)); +} \ No newline at end of file diff --git a/koala-wrapper/src/arkts-api/visitor.ts b/koala-wrapper/src/arkts-api/visitor.ts index becf519db..ccd5d27c3 100644 --- a/koala-wrapper/src/arkts-api/visitor.ts +++ b/koala-wrapper/src/arkts-api/visitor.ts @@ -46,6 +46,8 @@ import { isBlockExpression, isReturnStatement, isArrayExpression, + isTryStatement, + isBinaryExpression, } from '../generated'; import { isEtsScript, @@ -67,64 +69,6 @@ import { Es2pandaAstNodeType } from '../Es2pandaEnums'; type Visitor = (node: AstNode) => AstNode; -export interface StructVariableMetadata { - name: string; - properties: string[]; - modifiers: Es2pandaModifierFlags; - hasStateManagementType?: boolean; -} - -export class StructInfo { - metadata: Record = {}; - initializeBody: AstNode[] = []; - updateBody: AstNode[] = []; - isReusable: boolean = false; - toRecordBody: Property[] = []; -} - -export class GlobalInfo { - private _structCollection: Set; - private static instance: GlobalInfo; - private _structMap: Map; - - private constructor() { - this._structCollection = new Set(); - this._structMap = new Map(); - } - - public static getInfoInstance(): GlobalInfo { - if (!this.instance) { - this.instance = new GlobalInfo(); - } - return this.instance; - } - - public add(str: string): void { - this._structCollection.add(str); - } - - public getStructCollection(): Set { - return this._structCollection; - } - - public getStructInfo(structName: string): StructInfo { - const structInfo = this._structMap.get(structName); - if (!structInfo) { - return new StructInfo(); - } - return structInfo; - } - - public setStructInfo(structName: string, info: StructInfo): void { - this._structMap.set(structName, info); - } - - public reset(): void { - this._structMap.clear(); - this._structCollection.clear(); - } -} - // TODO: rethink (remove as) function nodeVisitor(node: T, visitor: Visitor): T { if (node === undefined) { @@ -156,6 +100,7 @@ export function visitEachChild(node: AstNode, visitor: Visitor): AstNode { script = visitStatement(script, visitor); script = visitOuterExpression(script, visitor); script = visitInnerExpression(script, visitor); + script = visitTrivialExpression(script, visitor); script = visitLiteral(script, visitor); // TODO return visitWithoutUpdate(script, visitor); @@ -263,6 +208,23 @@ function visitInnerExpression(node: AstNode, visitor: Visitor): AstNode { return node; } +function visitTrivialExpression(node: AstNode, visitor: Visitor): AstNode { + if (updated) { + return node; + } + if (isBinaryExpression(node)) { + updated = true; + return factory.updateBinaryExpression( + node, + nodeVisitor(node.left, visitor), + nodeVisitor(node.right, visitor), + node.operatorType + ); + } + // TODO + return node; +} + function visitDeclaration(node: AstNode, visitor: Visitor): AstNode { if (updated) { return node; @@ -381,6 +343,17 @@ function visitStatement(node: AstNode, visitor: Visitor): AstNode { updated = true; return factory.updateReturnStatement(node, nodeVisitor(node.argument, visitor)); } + if (isTryStatement(node)) { + updated = true; + return factory.updateTryStatement( + node, + nodeVisitor(node.block, visitor), + nodesVisitor(node.catchClauses, visitor), + nodeVisitor(node.finallyBlock, visitor), + [], + [] + ); + } // TODO return node; } diff --git a/koala-wrapper/src/generated/Es2pandaEnums.ts b/koala-wrapper/src/generated/Es2pandaEnums.ts index 1e5ee0d2c..a10e59e64 100644 --- a/koala-wrapper/src/generated/Es2pandaEnums.ts +++ b/koala-wrapper/src/generated/Es2pandaEnums.ts @@ -23,7 +23,7 @@ export enum Es2pandaContextState { ES2PANDA_STATE_ASM_GENERATED = 5, ES2PANDA_STATE_BIN_GENERATED = 6, ES2PANDA_STATE_ERROR = 7 -} + } // export enum Es2pandaAstNodeType { // AST_NODE_TYPE_ARROW_FUNCTION_EXPRESSION = 0, // AST_NODE_TYPE_ANNOTATION_DECLARATION = 1, diff --git a/koala-wrapper/src/generated/Es2pandaNativeModule.ts b/koala-wrapper/src/generated/Es2pandaNativeModule.ts index 8e4126db9..7dcfda5a9 100644 --- a/koala-wrapper/src/generated/Es2pandaNativeModule.ts +++ b/koala-wrapper/src/generated/Es2pandaNativeModule.ts @@ -877,9 +877,6 @@ export class Es2pandaNativeModule { _TSTypeAliasDeclarationSetTypeParameters(context: KNativePointer, receiver: KNativePointer, typeParams: KNativePointer): void { throw new Error("'TSTypeAliasDeclarationSetTypeParameters was not overloaded by native module initialization") } - _TSTypeAliasDeclarationAnnotations(context: KNativePointer, receiver: KNativePointer): KNativePointer { - throw new Error("'TSTypeAliasDeclarationAnnotations was not overloaded by native module initialization") - } _TSTypeAliasDeclarationAnnotationsConst(context: KNativePointer, receiver: KNativePointer): KNativePointer { throw new Error("'TSTypeAliasDeclarationAnnotationsConst was not overloaded by native module initialization") } @@ -1075,9 +1072,6 @@ export class Es2pandaNativeModule { _ScriptFunctionAddFlag(context: KNativePointer, receiver: KNativePointer, flags: KInt): void { throw new Error("'ScriptFunctionAddFlag was not overloaded by native module initialization") } - _ScriptFunctionAddModifier(context: KNativePointer, receiver: KNativePointer, flags: KInt): void { - throw new Error("'ScriptFunctionAddModifier was not overloaded by native module initialization") - } _ScriptFunctionFormalParamsLengthConst(context: KNativePointer, receiver: KNativePointer): KUInt { throw new Error("'ScriptFunctionFormalParamsLengthConst was not overloaded by native module initialization") } @@ -1498,6 +1492,18 @@ export class Es2pandaNativeModule { _ETSTupleSetTypeAnnotationsList(context: KNativePointer, receiver: KNativePointer, typeNodeList: BigUint64Array, typeNodeListSequenceLength: KUInt): void { throw new Error("'ETSTupleSetTypeAnnotationsList was not overloaded by native module initialization") } + _CreateTryStatement(context: KNativePointer, block: KNativePointer, catchClauses: BigUint64Array, catchClausesSequenceLength: KUInt, finalizer: KNativePointer, finalizerInsertionsLabelPair: BigUint64Array, finalizerInsertionsLabelPairSequenceLength: KUInt, finalizerInsertionsStatement: BigUint64Array, finalizerInsertionsStatementSequenceLength: KUInt): KNativePointer { + throw new Error("'CreateTryStatement was not overloaded by native module initialization") + } + _UpdateTryStatement(context: KNativePointer, original: KNativePointer, block: KNativePointer, catchClauses: BigUint64Array, catchClausesSequenceLength: KUInt, finalizer: KNativePointer, finalizerInsertionsLabelPair: BigUint64Array, finalizerInsertionsLabelPairSequenceLength: KUInt, finalizerInsertionsStatement: BigUint64Array, finalizerInsertionsStatementSequenceLength: KUInt): KNativePointer { + throw new Error("'UpdateTryStatement was not overloaded by native module initialization") + } + _CreateTryStatement1(context: KNativePointer, other: KNativePointer): KNativePointer { + throw new Error("'CreateTryStatement1 was not overloaded by native module initialization") + } + _UpdateTryStatement1(context: KNativePointer, original: KNativePointer, other: KNativePointer): KNativePointer { + throw new Error("'UpdateTryStatement1 was not overloaded by native module initialization") + } _TryStatementFinallyBlockConst(context: KNativePointer, receiver: KNativePointer): KNativePointer { throw new Error("'TryStatementFinallyBlockConst was not overloaded by native module initialization") } @@ -2116,9 +2122,6 @@ export class Es2pandaNativeModule { _ImportDeclarationSpecifiersConst(context: KNativePointer, receiver: KNativePointer): KNativePointer { throw new Error("'ImportDeclarationSpecifiersConst was not overloaded by native module initialization") } - _ImportDeclarationSpecifiers(context: KNativePointer, receiver: KNativePointer): KNativePointer { - throw new Error("'ImportDeclarationSpecifiers was not overloaded by native module initialization") - } _ImportDeclarationIsTypeKindConst(context: KNativePointer, receiver: KNativePointer): KBoolean { throw new Error("'ImportDeclarationIsTypeKindConst was not overloaded by native module initialization") } @@ -2152,9 +2155,6 @@ export class Es2pandaNativeModule { _ETSImportDeclarationIsPureDynamicConst(context: KNativePointer, receiver: KNativePointer): KBoolean { throw new Error("'ETSImportDeclarationIsPureDynamicConst was not overloaded by native module initialization") } - _ETSImportDeclarationAssemblerName(context: KNativePointer, receiver: KNativePointer): KStringPtr { - throw new Error("'ETSImportDeclarationAssemblerName was not overloaded by native module initialization") - } _ETSImportDeclarationAssemblerNameConst(context: KNativePointer, receiver: KNativePointer): KStringPtr { throw new Error("'ETSImportDeclarationAssemblerNameConst was not overloaded by native module initialization") } diff --git a/arkui-plugins/test/local/@ohos.arkui.component.d.ets b/koala-wrapper/src/generated/peers/LabelPair.ts similarity index 52% rename from arkui-plugins/test/local/@ohos.arkui.component.d.ets rename to koala-wrapper/src/generated/peers/LabelPair.ts index 0f74a9db4..c949e6fc1 100644 --- a/arkui-plugins/test/local/@ohos.arkui.component.d.ets +++ b/koala-wrapper/src/generated/peers/LabelPair.ts @@ -1,10 +1,10 @@ /* - * Copyright (C) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,10 +13,23 @@ * limitations under the License. */ -export * from "@ohos.arkui.component.customComponent"; -export * from "@ohos.arkui.component.common"; -export * from "@ohos.arkui.component.column"; -export * from "@ohos.arkui.component.text"; -export * from "@ohos.arkui.component.styledString"; -export * from "@ohos.arkui.component.enums"; -export * from "@ohos.arkui.component.units"; \ No newline at end of file +import { + global, + passNode, + passNodeArray, + unpackNonNullableNode, + unpackNode, + unpackNodeArray, + assertValidPeer, + AstNode, + KNativePointer, + nodeByType, + ArktsObject, + unpackString +} from "../../reexport-for-generated" + +export class LabelPair extends AstNode { + constructor(pointer: KNativePointer) { + super(pointer) + } +} \ No newline at end of file diff --git a/koala-wrapper/src/generated/peers/ScriptFunction.ts b/koala-wrapper/src/generated/peers/ScriptFunction.ts index 42c4c9343..69389b8d5 100644 --- a/koala-wrapper/src/generated/peers/ScriptFunction.ts +++ b/koala-wrapper/src/generated/peers/ScriptFunction.ts @@ -179,7 +179,7 @@ export class ScriptFunction extends AstNode { } /** @deprecated */ addModifier(flags: Es2pandaModifierFlags): this { - global.generatedEs2panda._ScriptFunctionAddModifier(global.context, this.peer, flags) + global.generatedEs2panda._AstNodeAddModifier(global.context, this.peer, flags) return this } get annotations(): readonly AnnotationUsage[] { diff --git a/koala-wrapper/src/generated/peers/TryStatement.ts b/koala-wrapper/src/generated/peers/TryStatement.ts index dd3a7571d..cbd6d830f 100644 --- a/koala-wrapper/src/generated/peers/TryStatement.ts +++ b/koala-wrapper/src/generated/peers/TryStatement.ts @@ -22,21 +22,30 @@ import { unpackNodeArray, assertValidPeer, AstNode, - Es2pandaAstNodeType, KNativePointer, nodeByType, ArktsObject, - unpackString + unpackString, + Es2pandaAstNodeType } from "../../reexport-for-generated" -import { Statement } from "./Statement" import { BlockStatement } from "./BlockStatement" import { CatchClause } from "./CatchClause" +import { LabelPair } from "./LabelPair" +import { Statement } from "./Statement" export class TryStatement extends Statement { - constructor(pointer: KNativePointer) { + constructor(pointer: KNativePointer) { assertValidPeer(pointer, Es2pandaAstNodeType.AST_NODE_TYPE_TRY_STATEMENT) super(pointer) - + } + static createTryStatement(block: BlockStatement | undefined, catchClauses: readonly CatchClause[], finalizer: BlockStatement | undefined, finalizerInsertionsLabelPair: readonly LabelPair[], finalizerInsertionsStatement: readonly Statement[]): TryStatement { + return new TryStatement(global.generatedEs2panda._CreateTryStatement(global.context, passNode(block), passNodeArray(catchClauses), catchClauses.length, passNode(finalizer), passNodeArray(finalizerInsertionsLabelPair), finalizerInsertionsLabelPair.length, passNodeArray(finalizerInsertionsStatement), finalizerInsertionsStatement.length)) + } + static updateTryStatement(original: TryStatement | undefined, block: BlockStatement | undefined, catchClauses: readonly CatchClause[], finalizer: BlockStatement | undefined, finalizerInsertionsLabelPair: readonly LabelPair[], finalizerInsertionsStatement: readonly Statement[]): TryStatement { + return new TryStatement(global.generatedEs2panda._UpdateTryStatement(global.context, passNode(original), passNode(block), passNodeArray(catchClauses), catchClauses.length, passNode(finalizer), passNodeArray(finalizerInsertionsLabelPair), finalizerInsertionsLabelPair.length, passNodeArray(finalizerInsertionsStatement), finalizerInsertionsStatement.length)) + } + static update1TryStatement(original?: TryStatement, other?: TryStatement): TryStatement { + return new TryStatement(global.generatedEs2panda._UpdateTryStatement1(global.context, passNode(original), passNode(other))) } get finallyBlock(): BlockStatement | undefined { return unpackNode(global.generatedEs2panda._TryStatementFinallyBlockConst(global.context, this.peer)) @@ -47,6 +56,9 @@ export class TryStatement extends Statement { get hasFinalizer(): boolean { return global.generatedEs2panda._TryStatementHasFinalizerConst(global.context, this.peer) } + get hasDefaultCatchClause(): boolean { + return global.generatedEs2panda._TryStatementHasDefaultCatchClauseConst(global.context, this.peer) + } get catchClauses(): readonly CatchClause[] { return unpackNodeArray(global.generatedEs2panda._TryStatementCatchClausesConst(global.context, this.peer)) } @@ -59,9 +71,9 @@ export class TryStatement extends Statement { return this } } -export function isTryStatement(node: AstNode): node is TryStatement { +export function isTryStatement(node: object | undefined): node is TryStatement { return node instanceof TryStatement } if (!nodeByType.has(Es2pandaAstNodeType.AST_NODE_TYPE_TRY_STATEMENT)) { nodeByType.set(Es2pandaAstNodeType.AST_NODE_TYPE_TRY_STATEMENT, TryStatement) -} +} \ No newline at end of file -- Gitee From ff61ae54ae38d1b11f9b4248f15fb6f9f7894f82 Mon Sep 17 00:00:00 2001 From: Yuxin Feng Date: Thu, 22 May 2025 11:51:46 +0800 Subject: [PATCH 2/3] update @Reusabe Transform Signed-off-by: Yuxin Feng Change-Id: Id0b6613fba44551b4bbac424f7b9c0552e461da8 --- .../decorators/reusable/reusable-basic.ets | 4 ++-- .../reusable/reusable-basic.test.ts | 21 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/arkui-plugins/test/demo/mock/decorators/reusable/reusable-basic.ets b/arkui-plugins/test/demo/mock/decorators/reusable/reusable-basic.ets index 755a647b3..bfbaaec54 100644 --- a/arkui-plugins/test/demo/mock/decorators/reusable/reusable-basic.ets +++ b/arkui-plugins/test/demo/mock/decorators/reusable/reusable-basic.ets @@ -1,5 +1,5 @@ import { Component, Reusable} from "@ohos.arkui.component" -import { State, Link } from "@ohos.arkui.stateManagement" +import { State, Prop } from "@ohos.arkui.stateManagement" @Component struct MyStateSample { @@ -11,7 +11,7 @@ struct MyStateSample { @Component @Reusable struct Child { - @Link num: number = 1 + @Prop num: number = 1 @State num1: number = 2 build() { diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index c9148c6e8..ebcacaff1 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -69,15 +69,18 @@ function main() {} @Component({freezeWhenInactive:false}) @Reusable() final class Child extends CustomComponent { public __initializeStruct(initializers: __Options_Child | undefined, @memo() content: (()=> void) | undefined): void { - if (({let gensym___98468840 = initializers; - (((gensym___98468840) == (null)) ? undefined : gensym___98468840.__backing_num)})) { - (this).__backing_num = new LinkDecoratedVariable("num", initializers!.__backing_num!); - }; - (this).__backing_num1 = new StateDecoratedVariable("num1", ((({let gensym___33833641 = initializers; - (((gensym___33833641) == (null)) ? undefined : gensym___33833641.num1)})) ?? (2))); + (this).__backing_num = new PropDecoratedVariable("num", ((({let gensym___83257243 = initializers; + (((gensym___83257243) == (null)) ? undefined : gensym___83257243.num)})) ?? (1))); + (this).__backing_num1 = new StateDecoratedVariable("num1", ((({let gensym___24398512 = initializers; + (((gensym___24398512) == (null)) ? undefined : gensym___24398512.num1)})) ?? (2))); } - public __updateStruct(initializers: __Options_Child | undefined): void {} + public __updateStruct(initializers: __Options_Child | undefined): void { + if (((({let gensym___108716469 = initializers; + (((gensym___108716469) == (null)) ? undefined : gensym___108716469.num)})) !== (undefined))) { + (this).__backing_num!.update((initializers!.num as number)); + } + } public override __toRecord(params: Object): Record { const paramsCasted = (params as __Options_Child); @@ -87,7 +90,7 @@ function main() {} }; } - private __backing_num?: LinkDecoratedVariable; + private __backing_num?: PropDecoratedVariable; public get num(): number { return (this).__backing_num!.get(); @@ -123,7 +126,7 @@ function main() {} @__Link_intrinsic() get num(): number | undefined set __backing_num(__backing_num: DecoratedV1VariableBase | undefined) - get __backing_num(): DecoratedV1VariableBase | undefined + get __backing_num(): PropDecoratedVariable | undefined set num1(num1: number | undefined) get num1(): number | undefined -- Gitee From 48be45309b7f2ed20dcda2983d519963ccabbad0 Mon Sep 17 00:00:00 2001 From: Jiakai Shi Date: Sat, 24 May 2025 21:14:42 +0800 Subject: [PATCH 3/3] rebase Signed-off-by: Jiakai Shi Change-Id: I2ec9319c6714b563bdb0f369fb58447166980397 --- .../custom-component-call.test.ts | 14 +- .../builder-param-passing.test.ts | 12 +- .../reusable/reusable-basic.test.ts | 13 +- arkui-plugins/test/utils/task-processor.ts | 39 +- .../ui-plugins/preprocessor-transform.ts | 6 - .../src/arkts-api/factory/nodeFactory.ts | 635 ++++++++++-------- .../src/arkts-api/utilities/performance.ts | 20 +- 7 files changed, 406 insertions(+), 333 deletions(-) diff --git a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts index 6d4a42235..52acbb4c5 100644 --- a/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/builder-lambda/custom-component/custom-component-call.test.ts @@ -57,14 +57,14 @@ import { Text as Text, Column as Column, Component as Component, Builder as Buil @Component() final class CustomContainerUser extends CustomComponent { public build() { - Column(undefined){ - CustomContainer(undefined){ - Column(undefined){ - Text("hello", undefined); + Column(){ + CustomContainer(){ + Column(){ + Text("hello"); }; }; CustomContainer(({} as __Options_CustomContainer)){ - Column(undefined){}; + Column(){}; }; CustomContainer(undefined){}; CustomContainer(); @@ -73,11 +73,11 @@ import { Text as Text, Column as Column, Component as Component, Builder as Buil public constructor() {} } -interface __Options_CustomContainer { +@Component() interface __Options_CustomContainer { @BuilderParam() closer?: (()=> void); } -interface __Options_CustomContainerUser { +@Component() interface __Options_CustomContainerUser { } `; diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts index 84bef3fa3..a44115f61 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/builder-param/builder-param-passing.test.ts @@ -78,7 +78,7 @@ function main() {} public __updateStruct(initializers: __Options_Parent | undefined): void {} @memo() public componentBuilder() { - Text(undefined, "Parent builder", undefined, undefined); + Text(undefined, "Parent builder"); } @memo() public _build(@memo() style: ((instance: Parent)=> Parent) | undefined, @memo() content: (()=> void) | undefined, initializers: __Options_Parent | undefined): void { @@ -87,19 +87,19 @@ function main() {} return new Child(); }), ({ customBuilderParam: (this).componentBuilder, - } as __Options_Child), undefined, undefined); + } as __Options_Child)); Child._instantiateImpl(undefined, (() => { return new Child(); }), ({ customBuilderParam: @memo() (() => { (this).componentBuilder(); }), - } as __Options_Child), undefined, undefined); + } as __Options_Child)); Child._instantiateImpl(undefined, (() => { return new Child(); - }), undefined, (() => { - Text(undefined, "Parent builder", undefined, undefined); - }), undefined); + }), undefined, undefined, (() => { + Text(undefined, "Parent builder"); + })); })); } private constructor() {} diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts index ebcacaff1..7b5b14409 100644 --- a/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts +++ b/arkui-plugins/test/ut/ui-plugins/decorators/reusable/reusable-basic.test.ts @@ -38,13 +38,12 @@ const reusableTransform: Plugins = { const pluginTester = new PluginTester('test basic reusable', buildConfig); const expectedScript: string = ` -import { DecoratedV1VariableBase as DecoratedV1VariableBase } from "@ohos.arkui.stateManagement"; import { StateDecoratedVariable as StateDecoratedVariable } from "@ohos.arkui.stateManagement"; -import { LinkDecoratedVariable as LinkDecoratedVariable } from "@ohos.arkui.stateManagement"; +import { PropDecoratedVariable as PropDecoratedVariable } from "@ohos.arkui.stateManagement"; import { memo as memo } from "@ohos.arkui.stateManagement"; import { CustomComponent as CustomComponent } from "@ohos.arkui.component"; import { Component as Component, Reusable as Reusable } from "@ohos.arkui.component"; -import { State as State, Link as Link } from "@ohos.arkui.stateManagement"; +import { State as State, Prop as Prop } from "@ohos.arkui.stateManagement"; function main() {} @@ -115,16 +114,16 @@ function main() {} private constructor() {} } -@Retention({policy:"SOURCE"}) @interface __Link_intrinsic {} + @Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } @Component({freezeWhenInactive:false}) @Reusable() interface __Options_Child { - @__Link_intrinsic() set num(num: number | undefined) + set num(num: number | undefined) - @__Link_intrinsic() get num(): number | undefined - set __backing_num(__backing_num: DecoratedV1VariableBase | undefined) + get num(): number | undefined + set __backing_num(__backing_num: PropDecoratedVariable | undefined) get __backing_num(): PropDecoratedVariable | undefined set num1(num1: number | undefined) diff --git a/arkui-plugins/test/utils/task-processor.ts b/arkui-plugins/test/utils/task-processor.ts index 666519197..df4d831d0 100644 --- a/arkui-plugins/test/utils/task-processor.ts +++ b/arkui-plugins/test/utils/task-processor.ts @@ -465,6 +465,24 @@ class TaskProcessor { this.worker.isIdle = true; console.log(`worker exiting...`); }); + this.emitter.on('TASK_COLLECT', (msg) => { + const jobId = msg.jobId; + const job = this.jobMap[jobId]; + const sourceType = job.isAbcJob ? 'abc' : 'external'; + const pluginStateId = msg.pluginStateId; + const pluginTestContext = msg.pluginTestContext as PluginTestContext; + const key = `${this.hashId}:${sourceType}:${pluginStateId}`; + let currentPluginTestContext; + if (PluginTestContextCache.getInstance().has(key)) { + currentPluginTestContext = { + ...PluginTestContextCache.getInstance().get(key), + ...pluginTestContext, + }; + } else { + currentPluginTestContext = pluginTestContext; + } + PluginTestContextCache.getInstance().set(key, currentPluginTestContext); + }); } async invokeWorkers(plugins: Plugins[], stopAfter?: PluginState): Promise { @@ -476,11 +494,9 @@ class TaskProcessor { files.push(job.fileList[i]); } }); - const fileInfo: CompileFileInfo = this.compileFiles.values().next().value!; const config = createGlobalConfig(fileInfo); const globalContextPtr = createGlobalContextPtr(config, files); - this.subscribe(); this.emitter.on('TASK_FINISH', (msg) => { this.worker.isIdle = true; @@ -509,25 +525,6 @@ class TaskProcessor { resolve(); } }); - this.emitter.on('TASK_COLLECT', (msg) => { - const jobId = msg.jobId; - const job = this.jobMap[jobId]; - const sourceType = job.isAbcJob ? 'abc' : 'external'; - const pluginStateId = msg.pluginStateId; - const pluginTestContext = msg.pluginTestContext as PluginTestContext; - const key = `${this.hashId}:${sourceType}:${pluginStateId}`; - let currentPluginTestContext; - if (PluginTestContextCache.getInstance().has(key)) { - currentPluginTestContext = { - ...PluginTestContextCache.getInstance().get(key), - ...pluginTestContext, - }; - } else { - currentPluginTestContext = pluginTestContext; - } - PluginTestContextCache.getInstance().set(key, currentPluginTestContext); - }); - this.worker = { isIdle: true }; this.assignTaskToIdleWorker(processingJobs, globalContextPtr, plugins, stopAfter); }); diff --git a/arkui-plugins/ui-plugins/preprocessor-transform.ts b/arkui-plugins/ui-plugins/preprocessor-transform.ts index c1e8e8e52..4b47576dd 100644 --- a/arkui-plugins/ui-plugins/preprocessor-transform.ts +++ b/arkui-plugins/ui-plugins/preprocessor-transform.ts @@ -200,16 +200,10 @@ export class PreprocessorTransformer extends AbstractVisitor { } visitor(node: arkts.AstNode): arkts.AstNode { - this.enter(node); const newNode = this.visitEachChild(node); if (arkts.isCallExpression(newNode) && this.isCustomConponentDecl(newNode)) { return this.transformComponentCall(newNode); } - if (arkts.isETSImportDeclaration(node)) { - this.addDependencesImport(node); - } else if (arkts.isEtsScript(node)) { - this.updateScriptWithImport(); - } return newNode; } } diff --git a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts index 2dc5361a0..0f9c3e283 100644 --- a/koala-wrapper/src/arkts-api/factory/nodeFactory.ts +++ b/koala-wrapper/src/arkts-api/factory/nodeFactory.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import { updateNodeByNode } from "../utilities/private" +import { updateNodeByNode } from '../utilities/private'; import { ArrowFunctionExpression, AssignmentExpression, @@ -29,10 +29,10 @@ import { StructDeclaration, VariableDeclaration, VariableDeclarator, - ETSStringLiteralType -} from "../types" -import { MemberExpression } from "../to-be-generated/MemberExpression" -import { AstNode } from "../peers/AstNode" + ETSStringLiteralType, +} from '../types'; +import { MemberExpression } from '../to-be-generated/MemberExpression'; +import { AstNode } from '../peers/AstNode'; import { AnnotationUsage, BinaryExpression, @@ -76,393 +76,462 @@ import { TemplateLiteral, ArrayExpression, AnnotationDeclaration, - TryStatement -} from "../../generated" -import { - Es2pandaModifierFlags -} from "../../generated/Es2pandaEnums" -import { - classPropertySetOptional, - hasModifierFlag -} from "../utilities/public" -import { updateIdentifier } from "../node-utilities/Identifier" -import { updateCallExpression } from "../node-utilities/CallExpression" -import { updateExpressionStatement } from "../node-utilities/ExpressionStatement" -import { updateMemberExpression } from "../node-utilities/MemberExpression" -import { updateFunctionDeclaration } from "../node-utilities/FunctionDeclaration" -import { updateBlockStatement } from "../node-utilities/BlockStatement" -import { updateArrowFunctionExpression } from "../node-utilities/ArrowFunctionExpression" -import { updateScriptFunction } from "../node-utilities/ScriptFunction" -import { updateStringLiteral } from "../node-utilities/StringLiteral" -import { updateNumberLiteral } from "../node-utilities/NumberLiteral" -import { updateETSParameterExpression } from "../node-utilities/ETSParameterExpression" -import { updateTSTypeParameter } from "../node-utilities/TSTypeParameter" -import { updateTSTypeParameterDeclaration } from "../node-utilities/TSTypeParameterDeclaration" -import { updateETSPrimitiveType } from "../node-utilities/ETSPrimitiveType" -import { updateETSTypeReference } from "../node-utilities/ETSTypeReference" -import { updateETSTypeReferencePart } from "../node-utilities/ETSTypeReferencePart" -import { updateETSImportDeclaration } from "../node-utilities/ETSImportDeclaration" -import { updateImportSpecifier } from "../node-utilities/ImportSpecifier" -import { updateVariableDeclaration } from "../node-utilities/VariableDeclaration" -import { updateVariableDeclarator } from "../node-utilities/VariableDeclarator" -import { updateETSUnionType } from "../node-utilities/ETSUnionType" -import { updateReturnStatement } from "../node-utilities/ReturnStatement" -import { updateIfStatement } from "../node-utilities/IfStatement" -import { updateBinaryExpression } from "../node-utilities/BinaryExpression" -import { updateClassDeclaration } from "../node-utilities/ClassDeclaration" -import { updateStructDeclaration } from "../node-utilities/StructDeclaration" -import { updateClassDefinition } from "../node-utilities/ClassDefinition" -import { updateClassProperty } from "../node-utilities/ClassProperty" -import { updateETSFunctionType } from "../node-utilities/ETSFunctionType" -import { updateFunctionExpression } from "../node-utilities/FunctionExpression" -import { updateMethodDefinition } from "../node-utilities/MethodDefinition" -import { updateSuperExpression } from "../node-utilities/SuperExpression" -import { updateTSTypeParameterInstantiation } from "../node-utilities/TSTypeParameterInstantiation" -import { updateTSInterfaceDeclaration } from "../node-utilities/TSInterfaceDeclaration" -import { updateTSInterfaceBody } from "../node-utilities/TSInterfaceBody" -import { updateUndefinedLiteral } from "../node-utilities/UndefinedLiteral" -import { updateAnnotationUsage, update1AnnotationUsage } from "../node-utilities/AnnotationUsage" -import { updateAssignmentExpression } from "../node-utilities/AssignmentExpression" -import { updateETSUndefinedType } from "../node-utilities/ETSUndefinedType" -import { updateConditionalExpression } from "../node-utilities/ConditionalExpression" -import { updateTSAsExpression } from "../node-utilities/TSAsExpression" -import { updateThisExpression } from "../node-utilities/ThisExpression" -import { updateTSTypeAliasDeclaration } from "../node-utilities/TSTypeAliasDeclaration" -import { updateTSNonNullExpression } from "../node-utilities/TSNonNullExpression" -import { updateChainExpression } from "../node-utilities/ChainExpression" -import { updateBlockExpression } from "../node-utilities/BlockExpression" -import { updateNullLiteral } from "../node-utilities/NullLiteral" -import { updateETSNewClassInstanceExpression } from "../node-utilities/ETSNewClassInstanceExpression" -import { updateObjectExpression } from "../node-utilities/ObjectExpression" -import { updateProperty } from "../node-utilities/Property" -import { updateTemplateLiteral } from "../node-utilities/TemplateLiteral" -import { updateArrayExpression } from "../node-utilities/ArrayExpression"; -import { updateAnnotationDeclaration } from "../node-utilities/AnnotationDeclaration" -import { updateTryStatement } from "../node-utilities/TryStatement" + TryStatement, +} from '../../generated'; +import { Es2pandaModifierFlags } from '../../generated/Es2pandaEnums'; +import { classPropertySetOptional, hasModifierFlag } from '../utilities/public'; +import { updateIdentifier } from '../node-utilities/Identifier'; +import { updateCallExpression } from '../node-utilities/CallExpression'; +import { updateExpressionStatement } from '../node-utilities/ExpressionStatement'; +import { updateMemberExpression } from '../node-utilities/MemberExpression'; +import { updateFunctionDeclaration } from '../node-utilities/FunctionDeclaration'; +import { updateBlockStatement } from '../node-utilities/BlockStatement'; +import { updateArrowFunctionExpression } from '../node-utilities/ArrowFunctionExpression'; +import { updateScriptFunction } from '../node-utilities/ScriptFunction'; +import { updateStringLiteral } from '../node-utilities/StringLiteral'; +import { updateNumberLiteral } from '../node-utilities/NumberLiteral'; +import { updateETSParameterExpression } from '../node-utilities/ETSParameterExpression'; +import { updateTSTypeParameter } from '../node-utilities/TSTypeParameter'; +import { updateTSTypeParameterDeclaration } from '../node-utilities/TSTypeParameterDeclaration'; +import { updateETSPrimitiveType } from '../node-utilities/ETSPrimitiveType'; +import { updateETSTypeReference } from '../node-utilities/ETSTypeReference'; +import { updateETSTypeReferencePart } from '../node-utilities/ETSTypeReferencePart'; +import { updateETSImportDeclaration } from '../node-utilities/ETSImportDeclaration'; +import { updateImportSpecifier } from '../node-utilities/ImportSpecifier'; +import { updateVariableDeclaration } from '../node-utilities/VariableDeclaration'; +import { updateVariableDeclarator } from '../node-utilities/VariableDeclarator'; +import { updateETSUnionType } from '../node-utilities/ETSUnionType'; +import { updateReturnStatement } from '../node-utilities/ReturnStatement'; +import { updateIfStatement } from '../node-utilities/IfStatement'; +import { updateBinaryExpression } from '../node-utilities/BinaryExpression'; +import { updateClassDeclaration } from '../node-utilities/ClassDeclaration'; +import { updateStructDeclaration } from '../node-utilities/StructDeclaration'; +import { updateClassDefinition } from '../node-utilities/ClassDefinition'; +import { updateClassProperty } from '../node-utilities/ClassProperty'; +import { updateETSFunctionType } from '../node-utilities/ETSFunctionType'; +import { updateFunctionExpression } from '../node-utilities/FunctionExpression'; +import { updateMethodDefinition } from '../node-utilities/MethodDefinition'; +import { updateSuperExpression } from '../node-utilities/SuperExpression'; +import { updateTSTypeParameterInstantiation } from '../node-utilities/TSTypeParameterInstantiation'; +import { updateTSInterfaceDeclaration } from '../node-utilities/TSInterfaceDeclaration'; +import { updateTSInterfaceBody } from '../node-utilities/TSInterfaceBody'; +import { updateUndefinedLiteral } from '../node-utilities/UndefinedLiteral'; +import { updateAnnotationUsage, update1AnnotationUsage } from '../node-utilities/AnnotationUsage'; +import { updateAssignmentExpression } from '../node-utilities/AssignmentExpression'; +import { updateETSUndefinedType } from '../node-utilities/ETSUndefinedType'; +import { updateConditionalExpression } from '../node-utilities/ConditionalExpression'; +import { updateTSAsExpression } from '../node-utilities/TSAsExpression'; +import { updateThisExpression } from '../node-utilities/ThisExpression'; +import { updateTSTypeAliasDeclaration } from '../node-utilities/TSTypeAliasDeclaration'; +import { updateTSNonNullExpression } from '../node-utilities/TSNonNullExpression'; +import { updateChainExpression } from '../node-utilities/ChainExpression'; +import { updateBlockExpression } from '../node-utilities/BlockExpression'; +import { updateNullLiteral } from '../node-utilities/NullLiteral'; +import { updateETSNewClassInstanceExpression } from '../node-utilities/ETSNewClassInstanceExpression'; +import { updateObjectExpression } from '../node-utilities/ObjectExpression'; +import { updateProperty } from '../node-utilities/Property'; +import { updateTemplateLiteral } from '../node-utilities/TemplateLiteral'; +import { updateArrayExpression } from '../node-utilities/ArrayExpression'; +import { updateAnnotationDeclaration } from '../node-utilities/AnnotationDeclaration'; +import { updateTryStatement } from '../node-utilities/TryStatement'; export const factory = { - get createIdentifier() { - return Identifier.create2Identifier + get createIdentifier(): (...args: Parameters) => Identifier { + return Identifier.create2Identifier; }, - get updateIdentifier() { - return updateIdentifier + get updateIdentifier(): (...args: Parameters) => Identifier { + return updateIdentifier; }, - get createCallExpression() { - return CallExpression.create + get createCallExpression(): (...args: Parameters) => CallExpression { + return CallExpression.create; }, - get updateCallExpression() { - return updateCallExpression + get updateCallExpression(): (...args: Parameters) => CallExpression { + return updateCallExpression; }, - get createExpressionStatement() { - return ExpressionStatement.create + get createExpressionStatement(): (...args: Parameters) => ExpressionStatement { + return ExpressionStatement.create; }, - get updateExpressionStatement() { - return updateExpressionStatement + get updateExpressionStatement(): (...args: Parameters) => ExpressionStatement { + return updateExpressionStatement; }, - get createMemberExpression() { - return MemberExpression.create + get createMemberExpression(): (...args: Parameters) => MemberExpression { + return MemberExpression.create; }, - get updateMemberExpression() { - return updateMemberExpression + get updateMemberExpression(): (...args: Parameters) => MemberExpression { + return updateMemberExpression; }, - get createEtsScript() { - return EtsScript.createFromSource + get createEtsScript(): (...args: Parameters) => EtsScript { + return EtsScript.createFromSource; }, - get updateEtsScript() { - return EtsScript.updateByStatements + get updateEtsScript(): (...args: Parameters) => EtsScript { + return EtsScript.updateByStatements; }, - get createFunctionDeclaration() { - return FunctionDeclaration.create + get createFunctionDeclaration(): (...args: Parameters) => FunctionDeclaration { + return FunctionDeclaration.create; }, - get updateFunctionDeclaration() { - return updateFunctionDeclaration + get updateFunctionDeclaration(): (...args: Parameters) => FunctionDeclaration { + return updateFunctionDeclaration; }, - get createBlock() { - return BlockStatement.createBlockStatement + get createBlock(): (...args: Parameters) => BlockStatement { + return BlockStatement.createBlockStatement; }, - get updateBlock() { - return updateBlockStatement + get updateBlock(): (...args: Parameters) => BlockStatement { + return updateBlockStatement; }, - get createArrowFunction() { - return ArrowFunctionExpression.create + get createArrowFunction(): (...args: Parameters) => ArrowFunctionExpression { + return ArrowFunctionExpression.create; }, - get updateArrowFunction() { - return updateArrowFunctionExpression + get updateArrowFunction(): (...args: Parameters) => ArrowFunctionExpression { + return updateArrowFunctionExpression; }, - get createScriptFunction() { - return ScriptFunction.createScriptFunction + get createScriptFunction(): (...args: Parameters) => ScriptFunction { + return ScriptFunction.createScriptFunction; }, - get updateScriptFunction() { - return updateScriptFunction + get updateScriptFunction(): (...args: Parameters) => ScriptFunction { + return updateScriptFunction; }, - get createStringLiteral() { - return StringLiteral.create1StringLiteral + get createStringLiteral(): (...args: Parameters) => StringLiteral { + return StringLiteral.create1StringLiteral; }, - get updateStringLiteral() { - return updateStringLiteral + get updateStringLiteral(): (...args: Parameters) => StringLiteral { + return updateStringLiteral; }, - get create1StringLiteral() { - return StringLiteral.create1StringLiteral + get create1StringLiteral(): (...args: Parameters) => StringLiteral { + return StringLiteral.create1StringLiteral; }, - get update1StringLiteral() { - return updateStringLiteral + get update1StringLiteral(): (...args: Parameters) => StringLiteral { + return updateStringLiteral; }, - get createNumericLiteral() { - return NumberLiteral.create + get createNumericLiteral(): (...args: Parameters) => NumberLiteral { + return NumberLiteral.create; }, - get updateNumericLiteral() { - return updateNumberLiteral + get updateNumericLiteral(): (...args: Parameters) => NumberLiteral { + return updateNumberLiteral; }, - get createParameterDeclaration() { - return ETSParameterExpression.create + get createParameterDeclaration(): ( + ...args: Parameters + ) => ETSParameterExpression { + return ETSParameterExpression.create; }, - get updateParameterDeclaration() { - return updateETSParameterExpression + get updateParameterDeclaration(): ( + ...args: Parameters + ) => ETSParameterExpression { + return updateETSParameterExpression; }, - get createTypeParameter() { - return TSTypeParameter.createTSTypeParameter + get createTypeParameter(): (...args: Parameters) => TSTypeParameter { + return TSTypeParameter.createTSTypeParameter; }, - get updateTypeParameter() { - return updateTSTypeParameter + get updateTypeParameter(): (...args: Parameters) => TSTypeParameter { + return updateTSTypeParameter; }, - get createTypeParameterDeclaration() { - return TSTypeParameterDeclaration.createTSTypeParameterDeclaration + get createTypeParameterDeclaration(): ( + ...args: Parameters + ) => TSTypeParameterDeclaration { + return TSTypeParameterDeclaration.createTSTypeParameterDeclaration; }, - get updateTypeParameterDeclaration() { - return updateTSTypeParameterDeclaration + get updateTypeParameterDeclaration(): ( + ...args: Parameters + ) => TSTypeParameterDeclaration { + return updateTSTypeParameterDeclaration; }, - get createPrimitiveType() { - return ETSPrimitiveType.createETSPrimitiveType + get createPrimitiveType(): ( + ...args: Parameters + ) => ETSPrimitiveType { + return ETSPrimitiveType.createETSPrimitiveType; }, - get updatePrimitiveType() { - return updateETSPrimitiveType + get updatePrimitiveType(): (...args: Parameters) => ETSPrimitiveType { + return updateETSPrimitiveType; }, - get createTypeReference() { - return ETSTypeReference.createETSTypeReference + get createTypeReference(): ( + ...args: Parameters + ) => ETSTypeReference { + return ETSTypeReference.createETSTypeReference; }, - get updateTypeReference() { - return updateETSTypeReference + get updateTypeReference(): (...args: Parameters) => ETSTypeReference { + return updateETSTypeReference; }, - get createTypeReferencePart() { - return ETSTypeReferencePart.createETSTypeReferencePart + get createTypeReferencePart(): ( + ...args: Parameters + ) => ETSTypeReferencePart { + return ETSTypeReferencePart.createETSTypeReferencePart; }, - get updateTypeReferencePart() { - return updateETSTypeReferencePart + get updateTypeReferencePart(): (...args: Parameters) => ETSTypeReferencePart { + return updateETSTypeReferencePart; }, - get createImportDeclaration() { - return ETSImportDeclaration.createETSImportDeclaration + get createImportDeclaration(): ( + ...args: Parameters + ) => ETSImportDeclaration { + return ETSImportDeclaration.createETSImportDeclaration; }, - get updateImportDeclaration() { - return updateETSImportDeclaration + get updateImportDeclaration(): (...args: Parameters) => ETSImportDeclaration { + return updateETSImportDeclaration; }, - get createImportSpecifier() { - return ImportSpecifier.createImportSpecifier + get createImportSpecifier(): ( + ...args: Parameters + ) => ImportSpecifier { + return ImportSpecifier.createImportSpecifier; }, - get updateImportSpecifier() { - return updateImportSpecifier + get updateImportSpecifier(): (...args: Parameters) => ImportSpecifier { + return updateImportSpecifier; }, - get createVariableDeclaration() { - return VariableDeclaration.create + get createVariableDeclaration(): (...args: Parameters) => VariableDeclaration { + return VariableDeclaration.create; }, - get updateVariableDeclaration() { - return updateVariableDeclaration + get updateVariableDeclaration(): (...args: Parameters) => VariableDeclaration { + return updateVariableDeclaration; }, - get createVariableDeclarator() { - return VariableDeclarator.create + get createVariableDeclarator(): (...args: Parameters) => VariableDeclarator { + return VariableDeclarator.create; }, - get updateVariableDeclarator() { - return updateVariableDeclarator + get updateVariableDeclarator(): (...args: Parameters) => VariableDeclarator { + return updateVariableDeclarator; }, - get createUnionType() { - return ETSUnionType.createETSUnionType + get createUnionType(): (...args: Parameters) => ETSUnionType { + return ETSUnionType.createETSUnionType; }, - get updateUnionType() { - return updateETSUnionType + get updateUnionType(): (...args: Parameters) => ETSUnionType { + return updateETSUnionType; }, - get createReturnStatement() { - return ReturnStatement.create1ReturnStatement + get createReturnStatement(): ( + ...args: Parameters + ) => ReturnStatement { + return ReturnStatement.create1ReturnStatement; }, - get updateReturnStatement() { - return updateReturnStatement + get updateReturnStatement(): (...args: Parameters) => ReturnStatement { + return updateReturnStatement; }, - get createIfStatement() { - return IfStatement.create + get createIfStatement(): (...args: Parameters) => IfStatement { + return IfStatement.create; }, - get updateIfStatement() { - return updateIfStatement + get updateIfStatement(): (...args: Parameters) => IfStatement { + return updateIfStatement; }, - get createBinaryExpression() { - return BinaryExpression.createBinaryExpression + get createBinaryExpression(): ( + ...args: Parameters + ) => BinaryExpression { + return BinaryExpression.createBinaryExpression; }, - get updateBinaryExpression() { - return updateBinaryExpression + get updateBinaryExpression(): (...args: Parameters) => BinaryExpression { + return updateBinaryExpression; }, - get createClassDeclaration() { - return ClassDeclaration.createClassDeclaration + get createClassDeclaration(): ( + ...args: Parameters + ) => ClassDeclaration { + return ClassDeclaration.createClassDeclaration; }, - get updateClassDeclaration() { - return updateClassDeclaration + get updateClassDeclaration(): (...args: Parameters) => ClassDeclaration { + return updateClassDeclaration; }, - get createStructDeclaration() { - return StructDeclaration.create + get createStructDeclaration(): (...args: Parameters) => StructDeclaration { + return StructDeclaration.create; }, - get updateStructDeclaration() { - return updateStructDeclaration + get updateStructDeclaration(): (...args: Parameters) => StructDeclaration { + return updateStructDeclaration; }, - get createClassDefinition() { - return ClassDefinition.createClassDefinition + get createClassDefinition(): ( + ...args: Parameters + ) => ClassDefinition { + return ClassDefinition.createClassDefinition; }, - get updateClassDefinition() { - return updateClassDefinition + get updateClassDefinition(): (...args: Parameters) => ClassDefinition { + return updateClassDefinition; }, - get createClassProperty() { - return ClassProperty.createClassProperty + get createClassProperty(): (...args: Parameters) => ClassProperty { + return ClassProperty.createClassProperty; }, - get updateClassProperty() { - return updateClassProperty + get updateClassProperty(): (...args: Parameters) => ClassProperty { + return updateClassProperty; }, - get createFunctionType() { - return ETSFunctionType.createETSFunctionType + get createFunctionType(): (...args: Parameters) => ETSFunctionType { + return ETSFunctionType.createETSFunctionType; }, - get updateFunctionType() { - return updateETSFunctionType + get updateFunctionType(): (...args: Parameters) => ETSFunctionType { + return updateETSFunctionType; }, - get createFunctionExpression() { - return FunctionExpression.create + get createFunctionExpression(): (...args: Parameters) => FunctionExpression { + return FunctionExpression.create; }, - get updateFunctionExpression() { - return updateFunctionExpression + get updateFunctionExpression(): (...args: Parameters) => FunctionExpression { + return updateFunctionExpression; }, - get createMethodDefinition() { - return MethodDefinition.create + get createMethodDefinition(): (...args: Parameters) => MethodDefinition { + return MethodDefinition.create; }, - get updateMethodDefinition() { - return updateMethodDefinition + get updateMethodDefinition(): (...args: Parameters) => MethodDefinition { + return updateMethodDefinition; }, - get createSuperExpression() { - return SuperExpression.createSuperExpression + get createSuperExpression(): ( + ...args: Parameters + ) => SuperExpression { + return SuperExpression.createSuperExpression; }, - get updateSuperExpression() { - return updateSuperExpression + get updateSuperExpression(): (...args: Parameters) => SuperExpression { + return updateSuperExpression; }, - get createTSTypeParameterInstantiation() { - return TSTypeParameterInstantiation.createTSTypeParameterInstantiation + get createTSTypeParameterInstantiation(): ( + ...args: Parameters + ) => TSTypeParameterInstantiation { + return TSTypeParameterInstantiation.createTSTypeParameterInstantiation; }, - get updateTSTypeParameterInstantiation() { - return updateTSTypeParameterInstantiation + get updateTSTypeParameterInstantiation(): ( + ...args: Parameters + ) => TSTypeParameterInstantiation { + return updateTSTypeParameterInstantiation; }, - get createInterfaceDeclaration() { - return TSInterfaceDeclaration.createTSInterfaceDeclaration + get createInterfaceDeclaration(): ( + ...args: Parameters + ) => TSInterfaceDeclaration { + return TSInterfaceDeclaration.createTSInterfaceDeclaration; }, - get updateInterfaceDeclaration() { - return updateTSInterfaceDeclaration + get updateInterfaceDeclaration(): ( + ...args: Parameters + ) => TSInterfaceDeclaration { + return updateTSInterfaceDeclaration; }, - get createInterfaceBody() { - return TSInterfaceBody.createTSInterfaceBody + get createInterfaceBody(): (...args: Parameters) => TSInterfaceBody { + return TSInterfaceBody.createTSInterfaceBody; }, - get updateInterfaceBody() { - return updateTSInterfaceBody + get updateInterfaceBody(): (...args: Parameters) => TSInterfaceBody { + return updateTSInterfaceBody; }, - get createUndefinedLiteral() { - return UndefinedLiteral.createUndefinedLiteral + get createUndefinedLiteral(): ( + ...args: Parameters + ) => UndefinedLiteral { + return UndefinedLiteral.createUndefinedLiteral; }, - get updateUndefinedLiteral() { - return updateUndefinedLiteral + get updateUndefinedLiteral(): (...args: Parameters) => UndefinedLiteral { + return updateUndefinedLiteral; }, - get createAnnotationDeclaration() { - return AnnotationDeclaration.create1AnnotationDeclaration + get createAnnotationDeclaration(): ( + ...args: Parameters + ) => AnnotationDeclaration { + return AnnotationDeclaration.create1AnnotationDeclaration; }, - get updateAnnotationDeclaration() { - return updateAnnotationDeclaration + get updateAnnotationDeclaration(): ( + ...args: Parameters + ) => AnnotationDeclaration { + return updateAnnotationDeclaration; }, - get createAnnotationUsage() { - return AnnotationUsage.createAnnotationUsage + get createAnnotationUsage(): ( + ...args: Parameters + ) => AnnotationUsage { + return AnnotationUsage.createAnnotationUsage; }, - get updateAnnotationUsage() { - return updateAnnotationUsage + get updateAnnotationUsage(): (...args: Parameters) => AnnotationUsage { + return updateAnnotationUsage; }, - get create1AnnotationUsage(): (...args: Parameters) => AnnotationUsage { + get create1AnnotationUsage(): ( + ...args: Parameters + ) => AnnotationUsage { return AnnotationUsage.create1AnnotationUsage; }, get update1AnnotationUsage(): (...args: Parameters) => AnnotationUsage { return update1AnnotationUsage; }, - get createAssignmentExpression() { - return AssignmentExpression.create + get createAssignmentExpression(): ( + ...args: Parameters + ) => AssignmentExpression { + return AssignmentExpression.create; }, - get updateAssignmentExpression() { - return updateAssignmentExpression + get updateAssignmentExpression(): (...args: Parameters) => AssignmentExpression { + return updateAssignmentExpression; }, - get createETSUndefinedType() { - return ETSUndefinedType.createETSUndefinedType + get createETSUndefinedType(): ( + ...args: Parameters + ) => ETSUndefinedType { + return ETSUndefinedType.createETSUndefinedType; }, - get updateETSUndefinedType() { - return updateETSUndefinedType + get updateETSUndefinedType(): (...args: Parameters) => ETSUndefinedType { + return updateETSUndefinedType; }, - get createFunctionSignature() { - return FunctionSignature.createFunctionSignature + get createFunctionSignature(): ( + ...args: Parameters + ) => FunctionSignature { + return FunctionSignature.createFunctionSignature; }, - get createConditionalExpression() { - return ConditionalExpression.createConditionalExpression + get createConditionalExpression(): ( + ...args: Parameters + ) => ConditionalExpression { + return ConditionalExpression.createConditionalExpression; }, - get updateConditionalExpression() { - return updateConditionalExpression + get updateConditionalExpression(): ( + ...args: Parameters + ) => ConditionalExpression { + return updateConditionalExpression; }, - get createTSAsExpression() { - return TSAsExpression.createTSAsExpression + get createTSAsExpression(): (...args: Parameters) => TSAsExpression { + return TSAsExpression.createTSAsExpression; }, - get updateTSAsExpression() { - return updateTSAsExpression + get updateTSAsExpression(): (...args: Parameters) => TSAsExpression { + return updateTSAsExpression; }, - get createThisExpression() { - return ThisExpression.createThisExpression + get createThisExpression(): (...args: Parameters) => ThisExpression { + return ThisExpression.createThisExpression; }, - get updateThisExpression() { - return updateThisExpression + get updateThisExpression(): (...args: Parameters) => ThisExpression { + return updateThisExpression; }, - get createTSTypeAliasDeclaration() { - return TSTypeAliasDeclaration.createTSTypeAliasDeclaration + get createTSTypeAliasDeclaration(): ( + ...args: Parameters + ) => TSTypeAliasDeclaration { + return TSTypeAliasDeclaration.createTSTypeAliasDeclaration; }, - get updateTSTypeAliasDeclaration() { - return updateTSTypeAliasDeclaration + get updateTSTypeAliasDeclaration(): ( + ...args: Parameters + ) => TSTypeAliasDeclaration { + return updateTSTypeAliasDeclaration; }, - get createTSNonNullExpression() { - return TSNonNullExpression.createTSNonNullExpression + get createTSNonNullExpression(): ( + ...args: Parameters + ) => TSNonNullExpression { + return TSNonNullExpression.createTSNonNullExpression; }, - get updateTSNonNullExpression() { - return updateTSNonNullExpression + get updateTSNonNullExpression(): (...args: Parameters) => TSNonNullExpression { + return updateTSNonNullExpression; }, - get createChainExpression() { - return ChainExpression.createChainExpression + get createChainExpression(): ( + ...args: Parameters + ) => ChainExpression { + return ChainExpression.createChainExpression; }, - get updateChainExpression() { - return updateChainExpression + get updateChainExpression(): (...args: Parameters) => ChainExpression { + return updateChainExpression; }, - get createBlockExpression() { - return BlockExpression.createBlockExpression + get createBlockExpression(): ( + ...args: Parameters + ) => BlockExpression { + return BlockExpression.createBlockExpression; }, - get updateBlockExpression() { - return updateBlockExpression + get updateBlockExpression(): (...args: Parameters) => BlockExpression { + return updateBlockExpression; }, - get createNullLiteral() { - return NullLiteral.createNullLiteral + get createNullLiteral(): (...args: Parameters) => NullLiteral { + return NullLiteral.createNullLiteral; }, - get updateNullLiteral() { - return updateNullLiteral + get updateNullLiteral(): (...args: Parameters) => NullLiteral { + return updateNullLiteral; }, - get createETSNewClassInstanceExpression() { - return ETSNewClassInstanceExpression.createETSNewClassInstanceExpression + get createETSNewClassInstanceExpression(): ( + ...args: Parameters + ) => ETSNewClassInstanceExpression { + return ETSNewClassInstanceExpression.createETSNewClassInstanceExpression; }, - get updateETSNewClassInstanceExpression() { - return updateETSNewClassInstanceExpression + get updateETSNewClassInstanceExpression(): ( + ...args: Parameters + ) => ETSNewClassInstanceExpression { + return updateETSNewClassInstanceExpression; }, - get createETSStringLiteralType() { + get createETSStringLiteralType(): ( + ...args: Parameters + ) => ETSStringLiteralType { return ETSStringLiteralType.create; }, get createBooleanLiteral(): (...args: Parameters) => BooleanLiteral { return BooleanLiteral.createBooleanLiteral; }, - get createObjectExpression(): (...args: Parameters) => ObjectExpression { + get createObjectExpression(): ( + ...args: Parameters + ) => ObjectExpression { return ObjectExpression.createObjectExpression; }, get updateObjectExpression(): (...args: Parameters) => ObjectExpression { @@ -474,13 +543,17 @@ export const factory = { get updateProperty(): (...args: Parameters) => Property { return updateProperty; }, - get createTemplateLiteral(): (...args: Parameters) => TemplateLiteral { + get createTemplateLiteral(): ( + ...args: Parameters + ) => TemplateLiteral { return TemplateLiteral.createTemplateLiteral; }, get updateTemplateLiteral(): (...args: Parameters) => TemplateLiteral { return updateTemplateLiteral; }, - get createArrayExpression(): (...args: Parameters) => ArrayExpression { + get createArrayExpression(): ( + ...args: Parameters + ) => ArrayExpression { return ArrayExpression.createArrayExpression; }, get updateArrayExpression(): (...args: Parameters) => ArrayExpression { @@ -494,6 +567,6 @@ export const factory = { }, /** @deprecated */ createTypeParameter1_(name: Identifier, constraint?: TypeNode, defaultType?: TypeNode) { - return TSTypeParameter.createTSTypeParameter(Identifier.create1Identifier(name.name), constraint, defaultType) + return TSTypeParameter.createTSTypeParameter(Identifier.create1Identifier(name.name), constraint, defaultType); }, -} +}; diff --git a/koala-wrapper/src/arkts-api/utilities/performance.ts b/koala-wrapper/src/arkts-api/utilities/performance.ts index 0c440b88a..bb9657084 100644 --- a/koala-wrapper/src/arkts-api/utilities/performance.ts +++ b/koala-wrapper/src/arkts-api/utilities/performance.ts @@ -67,7 +67,9 @@ export class Performance { } createEvent(name: string): Event { - if (this.shouldSkip) return { name: '', startTime: 0 }; + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } const startTime: number = performance.now(); const newEvent: Event = { name, startTime }; this.events.set(name, newEvent); @@ -76,7 +78,9 @@ export class Performance { } stopEvent(name: string, shouldLog: boolean = false): Event { - if (this.shouldSkip) return { name: '', startTime: 0 }; + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } if (!this.events.has(name) || this.scopes.length === 0) { throw new Error(`Event ${name} is not created.`); } @@ -104,7 +108,9 @@ export class Performance { } stopLastEvent(shouldLog: boolean = false): Event { - if (this.shouldSkip) return { name: '', startTime: 0 }; + if (this.shouldSkip) { + return { name: '', startTime: 0 }; + } if (this.scopes.length === 0) { throw new Error("No last event"); } @@ -132,7 +138,9 @@ export class Performance { } clearAllEvents(shouldLog: boolean = false): void { - if (this.shouldSkip) return; + if (this.shouldSkip) { + return; + } for (let i = 0; i < this.scopes.length; i ++) { this.stopLastEvent(shouldLog); } @@ -148,7 +156,9 @@ export class Performance { } visualizeEvents(shouldLog: boolean = false): void { - if (this.shouldSkip) return; + if (this.shouldSkip) { + return; + } const that = this; function buildVisualization(parentKey: string | null, indentLevel: number): [string, number] { const children = that.historyEvents.get(parentKey) || []; -- Gitee