diff --git a/arkui-plugins/common/arkts-utils.ts b/arkui-plugins/common/arkts-utils.ts index 771442543c1b92657853ff51a1ce076963d73781..6e9a5e38b23a5a479adb21ee5135986b77352e68 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 c6a98e6281f1f588c75fa2dabba57a1d9c904c7e..e7507328e44d783dea6b7e0f5a8800f630aee821 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 f0ad9ccb4f64d3b43318021289ab0c3e72c2ffa4..95843cb7b6d27b7fc3af59a6669544741e0625da 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 d4667b42435b00bd6044331a2781e55d0dbdae7b..33c27405c0743ce4fe054221405f2ea969fdfeea 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 a0a35f6c6db25f4ecbfbf05bc9123b7e381dadb4..54e0a298dbeca70277428831611a5d35feabb0c1 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 2ff6ea60ae0b042792ac8796396371e815a65a0e..899ef0c39b3dccec8dbbbe1fb68d6243a009dcc2 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 404892c3421d7bd8c181f910044cb00309512818..21c971ce0e3f65a6109399b782c0ea1b39998240 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 fa4a06bc4d2ab36313663c5a9fbe41a58aca5d0e..596077c04592dc3b33b647008e223f3c4d8191ab 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 58f785dbdbf39be44dfe531cffdef9daa64e5078..d1f8cbf866273ee63e52c952edbe1c6ab77b37a8 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 c1288e7ebb01fe323f5ba0e1f0c7cf51ea8826c7..fcc8f97d24e31cfc53d2feccf10a97eaf3ffabfc 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 d5e615e99daf12134c3c577318ae413dd070f823..a46f87a4e0d618d8af48cfa861d4a13d5945574d 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 61011461370ed949d955b31b005a7db91b863f94..d9721c60c131763244b8e862956abca5c5e75129 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 e013100ace975ee32863efd9adb8ba11935ac271..3e14da1c076e6138543e2a71a7ce8e324301c694 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 0267fb00dffdd82d8637dfb6471e70e6b883f042..75420af81786ffa48e32ebf34398eeab351cfaaf 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 3855891d1837393be886fb41105f72b95307f0df..0df152f9d1471a92d3e99f1855ed307fdf9ca0f5 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 acdb7c3c36ccd065e27692e8c22b6389c1b4e15c..a665975076ca05f9e8111b218136fdbff21f123c 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 4f0f3b5cf901bfd71f97ab91e53d2e33eee28531..50ef19686c214c0542fc50d5ab7d290f77160bd5 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 9cc3b09e07de69770a6f394122713c2a0853a371..e8a78a587e9d3eb84e4e8de3d68bdef4238183c5 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/decorators/reusable/reusable-basic.ets b/arkui-plugins/test/demo/mock/decorators/reusable/reusable-basic.ets index 755a647b3260f375089b04a907d481ce03f82dde..bfbaaec54035bf3f5a8254b1bf95b077376427b6 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/demo/mock/memo/functions/argument-call.ets b/arkui-plugins/test/demo/mock/memo/functions/argument-call.ets index 54263a55218737151cc173c8a8ef20ccddb6a699..acb0c7d65021315721e9fd8935923ba41e4c7fd8 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 ac8324d2211e079a3f6cbec9f2d1c26ceb53a123..8d11b8eeba07af3c97f9682f376474e1fe2edf04 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 313164b28bbb3b45af10444c109993013ce7350a..ceddf1eea2f87f76b913959b69f7c57c643270d2 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 cc0f993ec1eb1bb3ee0cea0548a4ab2e8fd8985a..0e2efd7741888ea0df8cb1d5686f409477fd8707 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 be715df9520f12300b9ccab2938677caa7572720..d8b38e4103eb8508ec5e207c6b10b7436d947de3 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 840c84aaf33c113cde341e668480a23f06dd6ed7..7ac6d38e67fa3ec6f0a44c5e94331c4bc60e088e 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 def28807a683db299c935b25e938d18a68fa300b..c840283188b0e3cc3400c102cdb920b64df638fa 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 08d252f583d623b7ad40503313053a66f4254a9c..46ac5cacf074fe1ae751ac01889844ce671e4d4c 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 fb757d8b65bc190fb1d3a7e8eb24e76131d8dd86..b1b80a22c94ff382e06d9f7bccbcb82d5fbd4502 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 b54c9c6c215117441391ad22670444ff65e684ef..424e210ffca4fdfd11e6fdd7ae198c9e6596a9ec 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 5f799140fdd1d8bfa485431799703a68446d6c88..08bcf33c07eb63997cc615b4c6a68c36336ac50d 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 2f4e2a401687e34c53dbd0c53e94a190edb6451f..2b058b77ca21289c4c12a388afc88c98fb7f170f 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 e28c853612e36b399f056c161e0d7a25842dd016..432d79624ff3d9fdb3955f9dc46ff4a2ffe5ec6c 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 ed3339dd17a1768970424b8401936d2716d0d8a3..e96c07df25b4e7cb15ca595a9ea4c994fe5800f6 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 725d2702b15a0360ac41262b23839816b65e4b1e..720a1df76aecc645766eb7955cb17eac7c7cc2f9 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 9fe1e5dc4ff19dfd5fd5ea76457b89863cbc6e5f..309dbd6c32d3f753500e897ace4a4144721c0dfa 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 ad61b2a7a49d2877344e5b1aff901f3739279579..50d691226757c08fb22f5e708d1ba1b1eb571ff5 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 c46a181e573a7bb02bb8f85c126744ebd7361a48..d7fa93fb36eec9f7f936c37ae4d448c4a3d63b31 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 728c949e75b926d8782cb3bc3fbb3b05ca67d079..0000000000000000000000000000000000000000 --- 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 4a0e94d6f089aab4442c94ca5d4f960aa70240af..0000000000000000000000000000000000000000 --- 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 5ba7ef75477458956a6042bd3a1b760903fcd89c..0000000000000000000000000000000000000000 --- 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 274947957808f9524d2fbf8746fffd2dd6934570..0000000000000000000000000000000000000000 --- 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 f70c0cb7f5ec72d10ec63b245007a17403df611c..0000000000000000000000000000000000000000 --- 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 a7257c839afaadfda0ce7c00942710078cb959aa..0000000000000000000000000000000000000000 --- 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 07123fbd761be13ee570397e4994ffff75d65231..34fcd06f257643b847cfab3cd038ba33af3a21fb 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 984a29adfe735c5a5e2085b0494ad066ed1beadd..0000000000000000000000000000000000000000 --- 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 cf9f7d191eab5ce015343fd51fb46337989f3bdc..d7640d7af073b46d8c90315b23e428895534a041 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 a3d7d2909665884324dfb5ca82cacde1f7be36f9..0580721bd2169485caaf8d9e0afdad194b99550d 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 db15946ae06df9c3a9bf9d0d1037a027fae86831..c589a44168b5d77e5a56d52f86ba9f80a7744baf 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 8e549464318354654d0303cbc1adda98572cd928..0fcc23735b4543c465111e0d8d40e0facba10926 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 53e3243e1162a4906a8db5b0e16c0c2e63ccdca2..efc062d40d8b8975555624d8a65bc2381f386d17 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 7db7cd676d57630897af74cb9328c96c2d64e75d..3a9f19848efdfaa737013bd4099479bc9d5da068 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 08c0eb3bdde9bba0673ab6a0c22cf7af771eda8c..639b0c61fd488f80e0b9a3ef99e528b714bfddff 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 f23a8d2529875eded121b1b681d55546030393d1..a9d1f2546aa66ab7d42797593b9b0cdd75d7f6a2 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 f023fef13b9f4a87a60269817fc05e53bd411580..f623bb63d2b8dd79d46fac90bf9731cf38ec4bc4 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 59b48a02458e04db484aca46c70396f2fca00a2d..56c92b9decc3af2ed6668f3210653292a77a2071 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 4f6e3fa92a6c7d7c4056ab836055e662fa0aa522..2076e3bc1da3a3e4041ec616366c22aead00bef4 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 de72519e74bbc1669122263ac6f136e10b4ce9fa..0d8dfbc7ff61cc0a61503a3aacd951e69df2aadf 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 7657e1dd0ce878e17e8df46d82fec626e2754e57..7a85fdba763ad7d5caefb734e742e0d22e81a8c5 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 0a669b4c085c2bf7abfc2c0cbd8e52c6bbaaf7b1..ed156ae94b8c5f03c2e6863da01a35f471d6e387 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 095b43a432d80471f09ab290c0ed4ab3e9c95406..57908bc9cded2aded771073196d8f38ca4db5b56 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 f8bba95f0399dc3673d7bd0f4535f2c2b89535ed..671ddee8ddb67bad3eeb087ceb9ad8a91ca16531 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 953742b8a28ebc4248b410680ccd4f4971dd75cb..67059cc64a197ccfa97a0ef32e63b3f198ea38f6 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 c912aba8d01acc56e9454ddde64ee19c650ef3e0..7f0b632984c5f1b87cf207f50ea5c0a4f9d1174e 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 3be2592364099f30d6e47d381bcd9f9d48a93afc..688ba5e7f4c4047b0480d1c74b96cac2be74667c 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 99053d0efc1ff8c0704aae5ef3e8a5bb7f94ba85..61e3c42549b72bd590bb544eef861a313f2dd7cc 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 cae171a655a066bc84bfb53561222f14ea013d02..df521d7e64265af2da3ed5da2255ef79741a891c 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 b9a0d5943b3976263962533eb7f9fc86253eb8a2..52acbb4c5912290ceee3a6a0f4a0fc45bbd0839e 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"; @@ -55,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(); @@ -71,11 +73,11 @@ import { Text as Text, Column as Column, Component as Component, Builder as Buil public constructor() {} } -interface __Options_CustomContainer { - closer?: @memo() (()=> void); +@Component() interface __Options_CustomContainer { + @BuilderParam() closer?: (()=> void); } -interface __Options_CustomContainerUser { +@Component() 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 37b4605ad3ed31255840b0017cae248b3f3258fb..261d5650815603dbed4b8b28aebc4f5806926e7a 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 ba63b9e2d3f79a811fb07922b3c14d811a15a9d8..a44115f61c7aa90f66c545752863981df7e14e6b 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() {} } @@ -81,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 { @@ -90,30 +87,30 @@ 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"); + })); })); } - 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 336ee7389e39279abbc73131d7d8a3ccb7f24244..17cd825c5d058079b4d2e544def2b220c940ff0a 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 09ffcfbaac0a5b7028f3ed9219e79d119222c8e1..0a36485c958d69769ec28e1d7dd4e55c5a2c387d 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 084238f23574add819cb0d465dbdafcc86092418..e737ffe84844d3c3f81a52f4dfa4d578965fc8da 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 5a798dab0e691772e75c0ed364690156b44f6886..29c368ffbe822296d49c7a9742ee7c0546ef6d6d 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 927e9122084b1ab539750f57e27bf6740c4645e7..fdfbfb35dc85554ac29c03da79ab24207b418235 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 6e903b6597738b247f6412b4faf6b90f6786a695..bf38c4bd02bf55d4c30bd36ffded09915099fbd9 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 300ebc5a94c97028d2a1ba2cf1f35d8fd67b1d60..b8d8017e27c6addb3a2220099be2b3e4eac5bdfb 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 55af0dd86e06af8eadae93c3f2ca4035e14f6ec5..9cbfac33e8d07d38f613362a2b322251bbd14027 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 becd4ced50ea497adef42adc1fd414bc288cfef1..f02f78f5112fba92af17482db72233538fde7efa 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 b0635b8a9c5997c72d8857abce0dd6221891ba22..6d875a0baecc705c8faf3a1ddd2f9d22225336a5 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 47237cf0ca7a4a4ac2f64fc829a44677b011eb0f..bdd7edd92acd2ede8f3ff1060edc01879aae8e09 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 c4239714b066f656bb88fdf244824700615f2e93..cc077de25b538d9cad24788b7a96e6b28b8e8c33 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 95a77ed88915dbb2a73196f3ee35e0c52de3919b..8767bdc86b8525d78c825cefd41e4f4b2a48a569 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 c21fe95f3a0a8e6660d8d7ab22e16bdb97a95bbe..20dbe50b4249118be475c3eb143a849bc8ae4960 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 b25b5c22d602668a0905928beaf36c34c454434f..215c88b788309e759dc8b9eaf81c0767ced7f1c3 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 312db0a77c1a5187996b32a4fe2361702aa0fbed..d6c049f751dacfbb28f580a845ec705c42b8da64 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 787797bc6ab6f78a392aec35edf47162fe8040f7..da5fbaff62655c13db92f017e2b44635960a778d 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 5239317ac0ae73263b62f23e175a9015c16b28c4..4fc7107220b651b5f150b19fc8751b6e83da6ad5 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 8ce1a14e59d7404b64729455ec23af72141017ec..4041764990d0462fb89b646917cad735d7d36c53 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 0a2eb5ae765b25c2a060f5875f79f8d2d62d9735..3aa06a1cce5f78ce2170138202a5ebe450284845 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 1925eef8318fa6916cd7486841a76a414835b506..a458fa042550b0f00c4d2e7d56a7049416c4dff1 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 60451251c9f9ef6de7aadcbe4aa038cae63b8fa9..b410d8b18e993e8a913a23f9b38a10797202d084 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 f4a20b03edf2d9383f546d73419ce38cba36e417..7b5b1440931dcddd233e200dc608cdcf7d2f9dac 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,23 +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 { 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() {} @@ -69,24 +59,27 @@ function main() {} return new Child(); }), ({ num: 5, - } as __Options_Child), undefined, "Child"); + } as __Options_Child), "Child"); } - public constructor() {} + private constructor() {} } @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); @@ -96,7 +89,7 @@ function main() {} }; } - private __backing_num?: LinkDecoratedVariable; + private __backing_num?: PropDecoratedVariable; public get num(): number { return (this).__backing_num!.get(); @@ -118,21 +111,21 @@ 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 { +@Component({freezeWhenInactive:false}) interface __Options_MyStateSample { } -interface __Options_Child { +@Component({freezeWhenInactive:false}) @Reusable() interface __Options_Child { set num(num: number | undefined) get num(): number | undefined - set __backing_num(__backing_num: DecoratedV1VariableBase | undefined) + set __backing_num(__backing_num: PropDecoratedVariable | undefined) - get __backing_num(): DecoratedV1VariableBase | undefined + get __backing_num(): PropDecoratedVariable | undefined set num1(num1: number | undefined) get num1(): number | undefined @@ -149,9 +142,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 dbbd614485278108aef6ace703ab34bef3d0e461..89be5603094be5efdb62b3bf5b460520db1136ff 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 a3258fa0b03149161fda147f74ee98526f794573..4203078ac407ad3e851fff9ec4a385153de9a038 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 eeec6cdc47afc73f1c978624058980c83312cddc..eae23bbe52cde8bffea2a34c3356048e92465b39 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 eb7d0a500504f760a5a576cc49fced391936bd96..c54a15e913041a601548492d9e441142f78bdfb5 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 8e183242807368b4734c879de7560d24e969de2d..0f47a5e8a0687a7a502f20830894c91124024841 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 c060b7a83627bf09c19499b2417df95bcbffddf3..7a17f62008b4a5a2c63ee42269f3efb4a43087ba 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 e129e2600ef4b19d85511ad851e8e2a87c65f31d..3d69b5f833600292d7854b3d4ee5619570895887 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 a403e00a94ab3a6cf5cb2f4be9c7e3628452c682..49ca6a6637ee95ed68cbd864f9527c6af1764915 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 aa649440be081a24bae30eb13931c614047accb7..892c35b0bdd085ee9963344e17b4c1eccfa546e5 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 c56d427353bc9635dcc22f78f06b451abe9f63de..92924efb90ee987c9085cf524a0e70fdd6c2296e 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 692bf1f24ec2566d2dcfad41a8b23e371795b146..83ebe0bcc21cfc4ba9fd57d6c02223a733f75922 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 46686c1e6b643fec4fc0d5e8e1c4d1cf0fb43114..58e9d3629c145e07a8ecf42df43b7ebf5dcec617 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 3474c59a2f94e9c921fb48e0cfbf6b797cf8ebf2..ad1751edd9aca71edab6992fad38d6942759b7af 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 b24fcdf64e0385cafb3d75e3c0785c4be61242e9..06942d1c4635afeecd940407dcfeabf77ca12db7 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 f893dae3b129643cef280ca4848cb5c4e70fe285..4d4495909aaa8ab10dee1a352fdd5ab6c15ee924 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 cbccd4afa9ac1174702cc789f8ddf6f842dece85..99ac287e3509cfb0e2a1963041d8d57cde8a71f0 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 e72c21ace10322a6fb0fdef80711a7d34bb98173..09e0b6d45678129575b7cbf005d65ef87163bbbb 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 608df6deec29a6afd1087b59ef8928a2949c0366..4712832cf5abbfe7f0d8e0e1acbb93a614a6ecf0 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 46ce7f562cc13bd90b3afd90b667cd2274c1e59b..451ecff9dbb20f8548847c25aa94fb7063ccbf8f 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 710456e21ed4557b0241b4f7da0491bc3a62c99a..78684a1f20675c83658c8a6bdcd99298350ee929 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 69e2b23adfc79c9fc7b138e1f011b07b6b092efb..f7d060b9f81437ff326ceb251ab718cb80d062e5 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 ff018cec51611f2fcc51485a17e185fca9ef357e..c953249a153babd7e3fc4ccdb1496ab2d7ab963a 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 085d3731e44fbfcb24b73b4b1d32843ce40bc849..2c3559df4107be301827c816f81442bba90b9abf 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 c564b71c780c590b555aec03d0b7b10db57fe7f6..87a7bdbd0cdec0fc276dacafed76f02403536644 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 14d494c050b2e384430a100c31fa94684ffef1e7..79c4d6c2e43e307c6bcbb732b441e2834a474f65 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 dec4b5296d0c13dceb7a2d3749e09306f2adb4a0..5fbc6c3fb4d7f04c8f2452611b3fb42abb0e07c5 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 728c06501cffc9330993fb6c4d91e3fec93c7bad..e622c5081e46d5022518bac7620ac19fc1718fe3 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 9cb01ec593ed40cc9c98940e4d1b8dcc9b7bdd33..99cd256431adf156d4218dcacaaf2117c8d772b9 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 0000000000000000000000000000000000000000..4582d42463e1122742553cf566bff301e18b9523 --- /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 0000000000000000000000000000000000000000..df4d831d06345dd955143706fbe98d864eae6ef3 --- /dev/null +++ b/arkui-plugins/test/utils/task-processor.ts @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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...`); + }); + 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 { + 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.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 32677ce448cc2c8909203b25292cb602a457f471..c29a9c01d10cbd817eff7c99d39650b318d9670f 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 5e4dc8331a4a365a1caded9ab0e231eb4cb37d2d..7a821bd742e711d0305963915f47fd25120a2e54 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 e4572d2f415f99321ad9b45361167bd6143953da..ebc67b04c16aebb6058f07091cdef2b453aa13be 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 c220640f56376a4841d6aa331811224e2e5de95b..51814013a5782ee75fbc086991169ed604a2b770 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 9ab64ff2b77871644e917a6718f0b0e89551c8aa..8539b023f9891bd4259a6fae71bae396a53ce182 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 75429bc424dd13ae6dd7e8bfff3cf5982c618637..82913eadc127c180966e1b98dcf97b0b6dd099b7 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 e2d04b3d2bdc1ce47beda8c1878c02ccbb353d59..9be8103ddfdcb3a47dc23548232ea2d1b74fc95d 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 c3b1dfbefc1fe994af7337fdf5f5ad687dc588e8..0d4d9dd9b4ed6b564c9a705f13e43c1f06c72897 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 0000000000000000000000000000000000000000..32337ca5b8dabd90cebb9c4bd1587636950a2b4d --- /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 76e2e6883f9e35619ed13126345036557710205e..a50014ecfaaa4482de0f3059feb2b273b93a3327 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 d6f90b49cf947e00c8b9a3193ee7fc319ca83dd0..4b47576dd91dd8cdbba1fe866c1c8f0e25b0eff7 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( @@ -250,18 +200,9 @@ 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); - } 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 4be00d1c8cca9781352e3477afcf32952e6aa32f..6601ab2828f13bc216f2b5078ae6580c8562ea6b 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 fbf600f066715a3f170c0f2bb9c9f07af511aedf..62b1f532bde7d68b966cc906ca6086192d42e722 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 bbb32deb1c9ffdfe306a05bf50c910e0843480c9..553f586c8ed3f2c964ab071eba1c6047ba9bd8c7 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 c1f610a4bf9c4ff43b0b5286ac50f8432f349c57..8bbeaab0a3767443d0791fbe322e49a8ad2d7afe 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 013eaa286d140d4664c074c678fa5e7f865be722..87c62c0ca6a5f39a4540baabf7eaebfd856f3aa4 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 eafd90c955bfc1232e20cb6549218f525d4642e3..f3c903310aaf3eda04b76a7f2ae2008eb5a8de81 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 a050e985294f30dcc9ddc5b92c4bcc8673eb18da..aa6272427d7ad1c9b97c047da76599695e45d101 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 d20d982cd7feb8f773a4cbf7ffb19e48cb4ab48d..ff734e899ec89d60b106ea4cb1b9264b93a73264 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 8da1283a269f18d813221d7c34db35c7f9f96a26..ec201c5a1010af3309384475ed8140bee12f1167 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 62bcad2d667b3aa8d069b41ceb1121adf659a7cf..6f77ede0762f7ea5fc5bf4343540f628583cafd6 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 b8bb3d9914cf0e37a87249cf2d94c899f0caab9c..f1b09a65d1555e0a67bc5762a036bdda8660a10a 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 144d1239a1d34d35c53518940cb2398ade5fd8cc..b084201c843abc10dd20c31fef8369920f452048 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 d89b471e77471008589650dea558d5d86e5e201c..a059055f45225e927929530747f8fa778d777126 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 667fabac74a82ac38516770170ca9f536560aa3c..b072d83e90f4da68d3e5d3946261b0cbc473ca3a 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 2693f749d866c47d3e6651bcb961979954473f58..2f12c29c9280e9ed4690f5a99641f4a21b30d368 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 efd83e9d60c3adc50a715613808566a85b108ef7..4ae94c30bee907ff4cd94e303d0d836bc2b901d8 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 b791a7da1c893b054ec9c591dddd2152cd681faa..24e9e3bf628b4cf0b57ac9301a5397fa1a8516b0 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 9005d8d884e291d837731f3349a60a7e112296a0..62b1583f3ac3e7a73af74621adca7605be7331b3 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 918d2ebac872e2e132fb509632213adb56994413..e11d44e74eb684a1fe1fa3d41b14748e3054fb41 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 be9ebdb11009ba304b153b32293d579e6feffa63..501e8d00af1d106e2c88c0666e8120aee98cb129 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 2af2176268987f3a1077635768f59a00735d2bd5..139e3d726df4cc31e701d39964cecffdbf99dd47 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 90fefdee5978c7fa0a04e740705cc03e39822983..5885848e790918d6ae2b4961476b266bc9676a33 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 73a22180b78ace4bc40068a85e91c5b33d76bcd4..4a657c3a120047dcff8d6709b4198db20f02129c 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 77ed29cf834d22aadbe3e55db9dba3991170b1fe..399d28d2229fe63c5d7a8f730469ef5694ccb3a0 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 31984c2ddffda64a64b6894e1f4807b6413e77ca..6dba4da149744e25cb6538b1e265f7e947ede3ff 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 eb7a6acb5a72bdb6aa5c096824a6603e6eecd0d3..c191814e16068e6108c1b27ddb284d9939148bc1 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 e1de4b1a1b14d16fe69ec41845aedd757f068cdf..d89b383f9462046f70aebb5ed3cebe73e231b121 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 78314c0cc462b4cba9eb0c31e6b4ba8a94fd9fb5..0c8bfb0a00a3d7920ba74fbaee68a5fc0d9f50f9 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 536c1ef3ff22c80472c53ebf3a49fca15517d597..0f9c3e283a14e2e47757d55f27f5978da8be7ee2 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, @@ -74,385 +74,464 @@ import { ObjectExpression, Property, TemplateLiteral, - ArrayExpression -} 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"; + 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'; export const factory = { - get createIdentifier() { - return Identifier.create2Identifier + get createIdentifier(): (...args: Parameters) => Identifier { + return Identifier.create2Identifier; + }, + get updateIdentifier(): (...args: Parameters) => Identifier { + return updateIdentifier; }, - get updateIdentifier() { - return updateIdentifier + get createCallExpression(): (...args: Parameters) => CallExpression { + return CallExpression.create; }, - get createCallExpression() { - return CallExpression.create + get updateCallExpression(): (...args: Parameters) => CallExpression { + return updateCallExpression; }, - get updateCallExpression() { - return updateCallExpression + get createExpressionStatement(): (...args: Parameters) => ExpressionStatement { + return ExpressionStatement.create; }, - get createExpressionStatement() { - return ExpressionStatement.create + get updateExpressionStatement(): (...args: Parameters) => ExpressionStatement { + return updateExpressionStatement; }, - get updateExpressionStatement() { - return updateExpressionStatement + get createMemberExpression(): (...args: Parameters) => MemberExpression { + return MemberExpression.create; }, - get createMemberExpression() { - return MemberExpression.create + get updateMemberExpression(): (...args: Parameters) => MemberExpression { + return updateMemberExpression; }, - get updateMemberExpression() { - return updateMemberExpression + get createEtsScript(): (...args: Parameters) => EtsScript { + return EtsScript.createFromSource; }, - get createEtsScript() { - return EtsScript.createFromSource + get updateEtsScript(): (...args: Parameters) => EtsScript { + return EtsScript.updateByStatements; }, - get updateEtsScript() { - return EtsScript.updateByStatements + get createFunctionDeclaration(): (...args: Parameters) => FunctionDeclaration { + return FunctionDeclaration.create; }, - get createFunctionDeclaration() { - return FunctionDeclaration.create + get updateFunctionDeclaration(): (...args: Parameters) => FunctionDeclaration { + return updateFunctionDeclaration; }, - get updateFunctionDeclaration() { - return updateFunctionDeclaration + get createBlock(): (...args: Parameters) => BlockStatement { + return BlockStatement.createBlockStatement; }, - get createBlock() { - return BlockStatement.createBlockStatement + get updateBlock(): (...args: Parameters) => BlockStatement { + return updateBlockStatement; }, - get updateBlock() { - return updateBlockStatement + get createArrowFunction(): (...args: Parameters) => ArrowFunctionExpression { + return ArrowFunctionExpression.create; }, - get createArrowFunction() { - return ArrowFunctionExpression.create + get updateArrowFunction(): (...args: Parameters) => ArrowFunctionExpression { + return updateArrowFunctionExpression; }, - get updateArrowFunction() { - return updateArrowFunctionExpression + get createScriptFunction(): (...args: Parameters) => ScriptFunction { + return ScriptFunction.createScriptFunction; }, - get createScriptFunction() { - return ScriptFunction.createScriptFunction + get updateScriptFunction(): (...args: Parameters) => ScriptFunction { + return updateScriptFunction; }, - get updateScriptFunction() { - return updateScriptFunction + get createStringLiteral(): (...args: Parameters) => StringLiteral { + return StringLiteral.create1StringLiteral; }, - get createStringLiteral() { - return StringLiteral.create1StringLiteral + get updateStringLiteral(): (...args: Parameters) => StringLiteral { + return updateStringLiteral; }, - get updateStringLiteral() { - return updateStringLiteral + get create1StringLiteral(): (...args: Parameters) => StringLiteral { + return StringLiteral.create1StringLiteral; }, - get create1StringLiteral() { - return StringLiteral.create1StringLiteral + get update1StringLiteral(): (...args: Parameters) => StringLiteral { + return updateStringLiteral; }, - get update1StringLiteral() { - return updateStringLiteral + get createNumericLiteral(): (...args: Parameters) => NumberLiteral { + return NumberLiteral.create; }, - get createNumericLiteral() { - return NumberLiteral.create + get updateNumericLiteral(): (...args: Parameters) => NumberLiteral { + return updateNumberLiteral; }, - get updateNumericLiteral() { - return updateNumberLiteral + get createParameterDeclaration(): ( + ...args: Parameters + ) => ETSParameterExpression { + return ETSParameterExpression.create; }, - get createParameterDeclaration() { - return ETSParameterExpression.create + get updateParameterDeclaration(): ( + ...args: Parameters + ) => ETSParameterExpression { + return updateETSParameterExpression; }, - get updateParameterDeclaration() { - return updateETSParameterExpression + get createTypeParameter(): (...args: Parameters) => TSTypeParameter { + return TSTypeParameter.createTSTypeParameter; }, - get createTypeParameter() { - return TSTypeParameter.createTSTypeParameter + get updateTypeParameter(): (...args: Parameters) => TSTypeParameter { + return updateTSTypeParameter; }, - get updateTypeParameter() { - return updateTSTypeParameter + get createTypeParameterDeclaration(): ( + ...args: Parameters + ) => TSTypeParameterDeclaration { + return TSTypeParameterDeclaration.createTSTypeParameterDeclaration; }, - get createTypeParameterDeclaration() { - return TSTypeParameterDeclaration.createTSTypeParameterDeclaration + get updateTypeParameterDeclaration(): ( + ...args: Parameters + ) => TSTypeParameterDeclaration { + return updateTSTypeParameterDeclaration; }, - get updateTypeParameterDeclaration() { - return updateTSTypeParameterDeclaration + get createPrimitiveType(): ( + ...args: Parameters + ) => ETSPrimitiveType { + return ETSPrimitiveType.createETSPrimitiveType; }, - get createPrimitiveType() { - return ETSPrimitiveType.createETSPrimitiveType + get updatePrimitiveType(): (...args: Parameters) => ETSPrimitiveType { + return updateETSPrimitiveType; }, - get updatePrimitiveType() { - return updateETSPrimitiveType + get createTypeReference(): ( + ...args: Parameters + ) => ETSTypeReference { + return ETSTypeReference.createETSTypeReference; }, - get createTypeReference() { - return ETSTypeReference.createETSTypeReference + get updateTypeReference(): (...args: Parameters) => ETSTypeReference { + return updateETSTypeReference; }, - get updateTypeReference() { - return updateETSTypeReference + get createTypeReferencePart(): ( + ...args: Parameters + ) => ETSTypeReferencePart { + return ETSTypeReferencePart.createETSTypeReferencePart; }, - get createTypeReferencePart() { - return ETSTypeReferencePart.createETSTypeReferencePart + get updateTypeReferencePart(): (...args: Parameters) => ETSTypeReferencePart { + return updateETSTypeReferencePart; }, - get updateTypeReferencePart() { - return updateETSTypeReferencePart + get createImportDeclaration(): ( + ...args: Parameters + ) => ETSImportDeclaration { + return ETSImportDeclaration.createETSImportDeclaration; }, - get createImportDeclaration() { - return ETSImportDeclaration.createETSImportDeclaration + get updateImportDeclaration(): (...args: Parameters) => ETSImportDeclaration { + return updateETSImportDeclaration; }, - get updateImportDeclaration() { - return updateETSImportDeclaration + get createImportSpecifier(): ( + ...args: Parameters + ) => ImportSpecifier { + return ImportSpecifier.createImportSpecifier; }, - get createImportSpecifier() { - return ImportSpecifier.createImportSpecifier + get updateImportSpecifier(): (...args: Parameters) => ImportSpecifier { + return updateImportSpecifier; }, - get updateImportSpecifier() { - return updateImportSpecifier + get createVariableDeclaration(): (...args: Parameters) => VariableDeclaration { + return VariableDeclaration.create; }, - get createVariableDeclaration() { - return VariableDeclaration.create + get updateVariableDeclaration(): (...args: Parameters) => VariableDeclaration { + return updateVariableDeclaration; }, - get updateVariableDeclaration() { - return updateVariableDeclaration + get createVariableDeclarator(): (...args: Parameters) => VariableDeclarator { + return VariableDeclarator.create; }, - get createVariableDeclarator() { - return VariableDeclarator.create + get updateVariableDeclarator(): (...args: Parameters) => VariableDeclarator { + return updateVariableDeclarator; }, - get updateVariableDeclarator() { - return updateVariableDeclarator + get createUnionType(): (...args: Parameters) => ETSUnionType { + return ETSUnionType.createETSUnionType; }, - get createUnionType() { - return ETSUnionType.createETSUnionType + get updateUnionType(): (...args: Parameters) => ETSUnionType { + return updateETSUnionType; }, - get updateUnionType() { - return updateETSUnionType + get createReturnStatement(): ( + ...args: Parameters + ) => ReturnStatement { + return ReturnStatement.create1ReturnStatement; }, - get createReturnStatement() { - return ReturnStatement.create1ReturnStatement + get updateReturnStatement(): (...args: Parameters) => ReturnStatement { + return updateReturnStatement; }, - get updateReturnStatement() { - return updateReturnStatement + get createIfStatement(): (...args: Parameters) => IfStatement { + return IfStatement.create; }, - get createIfStatement() { - return IfStatement.create + get updateIfStatement(): (...args: Parameters) => IfStatement { + return updateIfStatement; }, - get updateIfStatement() { - return updateIfStatement + get createBinaryExpression(): ( + ...args: Parameters + ) => BinaryExpression { + return BinaryExpression.createBinaryExpression; }, - get createBinaryExpression() { - return BinaryExpression.createBinaryExpression + get updateBinaryExpression(): (...args: Parameters) => BinaryExpression { + return updateBinaryExpression; }, - get updateBinaryExpression() { - return updateBinaryExpression + get createClassDeclaration(): ( + ...args: Parameters + ) => ClassDeclaration { + return ClassDeclaration.createClassDeclaration; }, - get createClassDeclaration() { - return ClassDeclaration.createClassDeclaration + get updateClassDeclaration(): (...args: Parameters) => ClassDeclaration { + return updateClassDeclaration; }, - get updateClassDeclaration() { - return updateClassDeclaration + get createStructDeclaration(): (...args: Parameters) => StructDeclaration { + return StructDeclaration.create; }, - get createStructDeclaration() { - return StructDeclaration.create + get updateStructDeclaration(): (...args: Parameters) => StructDeclaration { + return updateStructDeclaration; }, - get updateStructDeclaration() { - return updateStructDeclaration + get createClassDefinition(): ( + ...args: Parameters + ) => ClassDefinition { + return ClassDefinition.createClassDefinition; }, - get createClassDefinition() { - return ClassDefinition.createClassDefinition + get updateClassDefinition(): (...args: Parameters) => ClassDefinition { + return updateClassDefinition; }, - get updateClassDefinition() { - return updateClassDefinition + get createClassProperty(): (...args: Parameters) => ClassProperty { + return ClassProperty.createClassProperty; }, - get createClassProperty() { - return ClassProperty.createClassProperty + get updateClassProperty(): (...args: Parameters) => ClassProperty { + return updateClassProperty; }, - get updateClassProperty() { - return updateClassProperty + get createFunctionType(): (...args: Parameters) => ETSFunctionType { + return ETSFunctionType.createETSFunctionType; }, - get createFunctionType() { - return ETSFunctionType.createETSFunctionType + get updateFunctionType(): (...args: Parameters) => ETSFunctionType { + return updateETSFunctionType; }, - get updateFunctionType() { - return updateETSFunctionType + get createFunctionExpression(): (...args: Parameters) => FunctionExpression { + return FunctionExpression.create; }, - get createFunctionExpression() { - return FunctionExpression.create + get updateFunctionExpression(): (...args: Parameters) => FunctionExpression { + return updateFunctionExpression; }, - get updateFunctionExpression() { - return updateFunctionExpression + get createMethodDefinition(): (...args: Parameters) => MethodDefinition { + return MethodDefinition.create; }, - get createMethodDefinition() { - return MethodDefinition.create + get updateMethodDefinition(): (...args: Parameters) => MethodDefinition { + return updateMethodDefinition; }, - get updateMethodDefinition() { - return updateMethodDefinition + get createSuperExpression(): ( + ...args: Parameters + ) => SuperExpression { + return SuperExpression.createSuperExpression; }, - get createSuperExpression() { - return SuperExpression.createSuperExpression + get updateSuperExpression(): (...args: Parameters) => SuperExpression { + return updateSuperExpression; }, - get updateSuperExpression() { - return updateSuperExpression + get createTSTypeParameterInstantiation(): ( + ...args: Parameters + ) => TSTypeParameterInstantiation { + return TSTypeParameterInstantiation.createTSTypeParameterInstantiation; }, - get createTSTypeParameterInstantiation() { - return TSTypeParameterInstantiation.createTSTypeParameterInstantiation + get updateTSTypeParameterInstantiation(): ( + ...args: Parameters + ) => TSTypeParameterInstantiation { + return updateTSTypeParameterInstantiation; }, - get updateTSTypeParameterInstantiation() { - return updateTSTypeParameterInstantiation + get createInterfaceDeclaration(): ( + ...args: Parameters + ) => TSInterfaceDeclaration { + return TSInterfaceDeclaration.createTSInterfaceDeclaration; }, - get createInterfaceDeclaration() { - return TSInterfaceDeclaration.createTSInterfaceDeclaration + get updateInterfaceDeclaration(): ( + ...args: Parameters + ) => TSInterfaceDeclaration { + return updateTSInterfaceDeclaration; }, - get updateInterfaceDeclaration() { - return updateTSInterfaceDeclaration + get createInterfaceBody(): (...args: Parameters) => TSInterfaceBody { + return TSInterfaceBody.createTSInterfaceBody; }, - get createInterfaceBody() { - return TSInterfaceBody.createTSInterfaceBody + get updateInterfaceBody(): (...args: Parameters) => TSInterfaceBody { + return updateTSInterfaceBody; }, - get updateInterfaceBody() { - return updateTSInterfaceBody + get createUndefinedLiteral(): ( + ...args: Parameters + ) => UndefinedLiteral { + return UndefinedLiteral.createUndefinedLiteral; }, - get createUndefinedLiteral() { - return UndefinedLiteral.createUndefinedLiteral + get updateUndefinedLiteral(): (...args: Parameters) => UndefinedLiteral { + return updateUndefinedLiteral; }, - get updateUndefinedLiteral() { - return updateUndefinedLiteral + get createAnnotationDeclaration(): ( + ...args: Parameters + ) => AnnotationDeclaration { + return AnnotationDeclaration.create1AnnotationDeclaration; }, - get createAnnotationUsage() { - return AnnotationUsage.createAnnotationUsage + get updateAnnotationDeclaration(): ( + ...args: Parameters + ) => AnnotationDeclaration { + return updateAnnotationDeclaration; }, - get updateAnnotationUsage() { - return updateAnnotationUsage + get createAnnotationUsage(): ( + ...args: Parameters + ) => AnnotationUsage { + return AnnotationUsage.createAnnotationUsage; }, - get create1AnnotationUsage(): (...args: Parameters) => AnnotationUsage { + get updateAnnotationUsage(): (...args: Parameters) => AnnotationUsage { + return updateAnnotationUsage; + }, + 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 { @@ -464,20 +543,30 @@ 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 { 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) + 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 a77ec8acd050cd3dc4f68eb393a99bc08e27e281..b177455adbf67d6ffd54389cd262b9008c07e709 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 915dc5cebb40010bb552e9afc7e12b6b74ff64b6..345d95f213023ba56c28a1b1db72b9f222ec014e 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 d268c5d82c82ebaf1e94f106c367a684bd55f491..1d607b245d1ccb579317895894b35dafe5562bcd 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 0000000000000000000000000000000000000000..32512066cbba85065a851c78200a77277bd0cd75 --- /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 62a0b78d257036fa30639285875f363eddc9535e..e60cd5c061ebacc2b8971d1afea441a81b8cf43c 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 81a1ec31fc92a7bbd78fc4ab6f928633c11b43a5..b4bf7a203faa00c7eb776d1dfc428ff0d54a923d 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 5f3afbed2d791a58cd359de519e2a3d8412cff2e..5734dc4a49c3cd7ea1d897d1f00920d5dd032ab5 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 7e97b8a7c27a796d70d23daf503f440a43a28618..8e9f240922fe4320fa3a8cc2d045ac6904c7044a 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 bafe9df5d3e40028a56541ac3e73662df8c58f67..bb965708428f2447c7919d2bab2c5ceab2076a27 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; @@ -60,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); @@ -69,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.`); } @@ -82,19 +93,24 @@ 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 { - 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"); } @@ -107,19 +123,24 @@ 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 { - if (this.shouldSkip) return; + if (this.shouldSkip) { + return; + } for (let i = 0; i < this.scopes.length; i ++) { this.stopLastEvent(shouldLog); } @@ -129,4 +150,37 @@ 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 1ebdd1b2623fe7af14cd8c7775d82497b7ad8f29..a22803cf0eebe63d08e8055bb0b16bed06562d72 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 becf519db2d713e56c4dab0217230b5063819827..ccd5d27c3420ea529c922bc4c61bee84750acebf 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 1e5ee0d2c482bbc7844c58134580b5f277e611cc..a10e59e6482833abd56ad9585a8f9e6fe2b202d0 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 8e4126db90bb5e70942caceffa2f531cc863ccba..7dcfda5a9e6fd221976438214656a28cdb7b1448 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 0f74a9db4523b49fbb41c6f94bf1ca39b66f1fba..c949e6fc1e8803594a320aaf5b33c8f946c4975e 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 42c4c9343e2b2c15fcc6f8ff687f96fe887b57da..69389b8d510264ca96f44f46aa2495907074f973 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 dd3a7571d321bd528838b640530a3ce8c1b2d664..cbd6d830fc7d1a66d5d3b665c985b9e088ca7bca 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