diff --git a/arkui-plugins/common/predefines.ts b/arkui-plugins/common/predefines.ts index db95432b858919afb42776ef74cdfd05635ce867..f6a07618195408c42c73d88b141238bb2609257c 100644 --- a/arkui-plugins/common/predefines.ts +++ b/arkui-plugins/common/predefines.ts @@ -212,6 +212,7 @@ export enum StateManagementTypes { MAKE_PROP = 'makeProp', MAKE_PROP_REF = 'makePropRef', MAKE_LOCAL = 'makeLocal', + MAKE_STATIC_LOCAL = 'makeStaticLocal', MAKE_STORAGE_PROP_REF = 'makeStoragePropRef', MAKE_LOCAL_STORAGE_PROP_REF = 'makeLocalStoragePropRef', MAKE_STORAGE_LINK = 'makeStorageLink', diff --git a/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets b/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets new file mode 100644 index 0000000000000000000000000000000000000000..51836622cb772e4521c71243f55e6e60103442a9 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/computed/static-computed.ets @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentV2 } from "@ohos.arkui.component"; +import { Computed, ObservedV2, Trace, Local } from "@ohos.arkui.stateManagement"; + +@ObservedV2 +class Name { + @Trace static firstName: string = 'Hua'; + @Trace static lastName: string = 'Li'; + + @Computed + static get fullName(): string { + return Name.firstName + ' ' + Name.lastName; + } +} + +@ComponentV2 +struct Parent { + @Local static localVar1: string = 'stateVar1'; + @Local static localVar2: number = 50; + + + @Computed + static get fullName(): string { + return Parent.localVar1; + } + + build() {} +} diff --git a/arkui-plugins/test/demo/mock/decorators/local/static-local.ets b/arkui-plugins/test/demo/mock/decorators/local/static-local.ets new file mode 100644 index 0000000000000000000000000000000000000000..4d84fcbc2f1c9dd6ddcc2a3ac132711888cdb2c1 --- /dev/null +++ b/arkui-plugins/test/demo/mock/decorators/local/static-local.ets @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentV2 } from "@ohos.arkui.component"; +import { Local } from "@ohos.arkui.stateManagement"; + +class ABB {} + +@ComponentV2 +struct Parent { + @Local static localVar1: string = 'stateVar1'; + @Local static localVar2: number = 50; + @Local static localVar3: ABB = new ABB(); + + build() {} +} \ No newline at end of file diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3471435a964c4d48b54e7625177189028ff340d6 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/computed/static-computed.test.ts @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { uiNoRecheck, recheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const BUILDER_LAMBDA_DIR_PATH: string = 'decorators/computed'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, BUILDER_LAMBDA_DIR_PATH, 'static-computed.ets'), +]; + +const pluginTester = new PluginTester('test @Computed decorated static getter method', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { IObservedObject as IObservedObject } from "arkui.stateManagement.decorator"; + +import { UIUtils as UIUtils } from "arkui.stateManagement.utils"; + +import { IMutableStateMeta as IMutableStateMeta } from "arkui.stateManagement.decorator"; + +import { RenderIdType as RenderIdType } from "arkui.stateManagement.decorator"; + +import { WatchIdType as WatchIdType } from "arkui.stateManagement.decorator"; + +import { ISubscribedWatches as ISubscribedWatches } from "arkui.stateManagement.decorator"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; + +import { ComponentV2 as ComponentV2 } from "@ohos.arkui.component"; + +import { Computed as Computed, ObservedV2 as ObservedV2, Trace as Trace, Local as Local } from "@ohos.arkui.stateManagement"; + +function main() {} + +@ObservedV2() class Name implements IObservedObject, ISubscribedWatches { + @JSONStringifyIgnore() private subscribedWatches: ISubscribedWatches = STATE_MGMT_FACTORY.makeSubscribedWatches(); + + public addWatchSubscriber(watchId: WatchIdType): void { + this.subscribedWatches.addWatchSubscriber(watchId); + } + + public removeWatchSubscriber(watchId: WatchIdType): boolean { + return this.subscribedWatches.removeWatchSubscriber(watchId); + } + + public executeOnSubscribingWatches(propertyName: string): void { + this.subscribedWatches.executeOnSubscribingWatches(propertyName); + } + + public setV1RenderId(renderId: RenderIdType): void {} + + protected conditionalAddRef(meta: IMutableStateMeta): void { + meta.addRef(); + } + + @JSONRename({newName:"firstName"}) public static __backing_firstName: string = "Hua"; + + @JSONStringifyIgnore() public static __meta_firstName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + + @JSONRename({newName:"lastName"}) public static __backing_lastName: string = "Li"; + + @JSONStringifyIgnore() public static __meta_lastName: IMutableStateMeta = STATE_MGMT_FACTORY.makeMutableStateMeta(); + + public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + return ((((Name.firstName) + (" "))) + (Name.lastName)); + }), "fullName"); + + @Computed() public static get fullName(): string { + return Name.__computed_fullName.get(); + } + + static { + + } + public static get firstName(): string { + Name.__meta_firstName.addRef(); + return UIUtils.makeObserved(Name.__backing_firstName); + } + + public static set firstName(newValue: string) { + if (((Name.__backing_firstName) !== (newValue))) { + Name.__backing_firstName = newValue; + Name.__meta_firstName.fireChange(); + } + } + + public static get lastName(): string { + Name.__meta_lastName.addRef(); + return UIUtils.makeObserved(Name.__backing_lastName); + } + + public static set lastName(newValue: string) { + if (((Name.__backing_lastName) !== (newValue))) { + Name.__backing_lastName = newValue; + Name.__meta_lastName.fireChange(); + } + } + + public constructor() {} + +} + +@ComponentV2() final struct Parent extends CustomComponentV2 { + public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_Parent | undefined)): void {} + + public static __backing_localVar1: ILocalDecoratedVariable = STATE_MGMT_FACTORY.makeLocal(null, "localVar1", "stateVar1"); + + public static get localVar1(): string { + return Parent.__backing_localVar1.get(); + } + + public static set localVar1(value: string) { + Parent.__backing_localVar1.set(value); + } + + public static __backing_localVar2: ILocalDecoratedVariable = STATE_MGMT_FACTORY.makeLocal(null, "localVar2", 50); + + public static get localVar2(): number { + return Parent.__backing_localVar2.get(); + } + + public static set localVar2(value: number) { + Parent.__backing_localVar2.set(value); + } + + public static __computed_fullName = STATE_MGMT_FACTORY.makeComputed((() => { + return Parent.localVar1; + }), "fullName"); + + @Computed() public static get fullName(): string { + return Parent.__computed_fullName.get(); + } + + @memo() public build() {} + + private constructor() {} + + static { + + } +} + +@ComponentV2() export interface __Options_Parent { + set localVar1(localVar1: (string | undefined)) + + get localVar1(): (string | undefined) + set __backing_localVar1(__backing_localVar1: (ILocalDecoratedVariable | undefined)) + + get __backing_localVar1(): (ILocalDecoratedVariable | undefined) + set localVar2(localVar2: (number | undefined)) + + get localVar2(): (number | undefined) + set __backing_localVar2(__backing_localVar2: (ILocalDecoratedVariable | undefined)) + + get __backing_localVar2(): (ILocalDecoratedVariable | undefined) + +} +`; + +function testCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test @Computed decorated static getter method', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts b/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..894a5b5396858e98eb540d5a02e52fa0a5aa02a0 --- /dev/null +++ b/arkui-plugins/test/ut/ui-plugins/decorators/local/static-local.test.ts @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as path from 'path'; +import { PluginTester } from '../../../../utils/plugin-tester'; +import { mockBuildConfig } from '../../../../utils/artkts-config'; +import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../../utils/path-config'; +import { parseDumpSrc } from '../../../../utils/parse-string'; +import { recheck, uiNoRecheck } from '../../../../utils/plugins'; +import { BuildConfig, PluginTestContext } from '../../../../utils/shared-types'; +import { uiTransform } from '../../../../../ui-plugins'; +import { Plugins } from '../../../../../common/plugin-context'; + +const STATE_DIR_PATH: string = 'decorators/local'; + +const buildConfig: BuildConfig = mockBuildConfig(); +buildConfig.compileFiles = [ + path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, STATE_DIR_PATH, 'static-local.ets'), +]; + +const pluginTester = new PluginTester('test static @Local decorated variables transformation', buildConfig); + +const parsedTransform: Plugins = { + name: 'parsedTrans', + parsed: uiTransform().parsed +}; + +const expectedScript: string = ` +import { memo as memo } from "arkui.stateManagement.runtime"; + +import { STATE_MGMT_FACTORY as STATE_MGMT_FACTORY } from "arkui.stateManagement.decorator"; + +import { ILocalDecoratedVariable as ILocalDecoratedVariable } from "arkui.stateManagement.decorator"; + +import { CustomComponentV2 as CustomComponentV2 } from "arkui.component.customComponent"; + +import { ComponentV2 as ComponentV2 } from "@ohos.arkui.component"; + +import { Local as Local } from "@ohos.arkui.stateManagement"; + +function main() {} + +class ABB { + public constructor() {} + +} + +@ComponentV2() final struct Parent extends CustomComponentV2 { + public __initializeStruct(initializers: (__Options_Parent | undefined), @memo() content: ((()=> void) | undefined)): void {} + + public __updateStruct(initializers: (__Options_Parent | undefined)): void {} + + public static __backing_localVar1: ILocalDecoratedVariable = STATE_MGMT_FACTORY.makeStaticLocal("localVar1", "stateVar1"); + + public static get localVar1(): string { + return Parent.__backing_localVar1.get(); + } + + public static set localVar1(value: string) { + Parent.__backing_localVar1.set(value); + } + + public static __backing_localVar2: ILocalDecoratedVariable = STATE_MGMT_FACTORY.makeStaticLocal("localVar2", 50); + + public static get localVar2(): number { + return Parent.__backing_localVar2.get(); + } + + public static set localVar2(value: number) { + Parent.__backing_localVar2.set(value); + } + + public static __backing_localVar3: ILocalDecoratedVariable = STATE_MGMT_FACTORY.makeStaticLocal("localVar3", new ABB()); + + public static get localVar3(): ABB { + return Parent.__backing_localVar3.get(); + } + + public static set localVar3(value: ABB) { + Parent.__backing_localVar3.set(value); + } + + @memo() public build() {} + + private constructor() {} + + static { + + } +} + +@ComponentV2() export interface __Options_Parent { + set localVar1(localVar1: (string | undefined)) + + get localVar1(): (string | undefined) + set __backing_localVar1(__backing_localVar1: (ILocalDecoratedVariable | undefined)) + + get __backing_localVar1(): (ILocalDecoratedVariable | undefined) + set localVar2(localVar2: (number | undefined)) + + get localVar2(): (number | undefined) + set __backing_localVar2(__backing_localVar2: (ILocalDecoratedVariable | undefined)) + + get __backing_localVar2(): (ILocalDecoratedVariable | undefined) + set localVar3(localVar3: (ABB | undefined)) + + get localVar3(): (ABB | undefined) + set __backing_localVar3(__backing_localVar3: (ILocalDecoratedVariable | undefined)) + + get __backing_localVar3(): (ILocalDecoratedVariable | undefined) + +} +`; + +function testParsedAndCheckedTransformer(this: PluginTestContext): void { + expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); +} + +pluginTester.run( + 'test static @Local decorated variables transformation', + [parsedTransform, uiNoRecheck, recheck], + { + 'checked:ui-no-recheck': [testParsedAndCheckedTransformer], + }, + { + stopAfter: 'checked', + } +); diff --git a/arkui-plugins/ui-plugins/property-translators/computed.ts b/arkui-plugins/ui-plugins/property-translators/computed.ts index ea973965498b9de27a2a7a682af7f20350ed81de..8e5cc573ae2be4963a059f43fc84770b530ca3e9 100644 --- a/arkui-plugins/ui-plugins/property-translators/computed.ts +++ b/arkui-plugins/ui-plugins/property-translators/computed.ts @@ -17,7 +17,7 @@ import * as arkts from '@koalaui/libarkts'; import { expectName } from '../../common/arkts-utils'; import { GetSetTypes, StateManagementTypes } from '../../common/predefines'; -import { computedField } from '../utils'; +import { ClassInfo, computedField } from '../utils'; import { generateThisBacking, generateGetOrSetCall, getGetterReturnType } from './utils'; import { MethodTranslator } from './base'; import { InitializerConstructor } from './types'; @@ -25,6 +25,13 @@ import { factory as UIFactory } from '../ui-factory'; import { factory } from './factory'; export class ComputedTranslator extends MethodTranslator implements InitializerConstructor { + private isStatic: boolean; + + constructor(method: arkts.MethodDefinition, classInfo: ClassInfo) { + super(method, classInfo); + this.isStatic = this.method.isStatic; + } + translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.method.name); const newName: string = computedField(originalName); @@ -37,6 +44,7 @@ export class ComputedTranslator extends MethodTranslator implements InitializerC cacheTranslatedInitializer(newName: string): void {} translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { + const modifiers = this.isStatic ? this.method.modifiers : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE; const field: arkts.ClassProperty = arkts.factory.createClassProperty( arkts.factory.createIdentifier(newName), factory.generateStateMgmtFactoryCall( @@ -46,7 +54,7 @@ export class ComputedTranslator extends MethodTranslator implements InitializerC arkts.factory.createArrowFunction( UIFactory.createScriptFunction({ body: this.method.scriptFunction.body?.clone(), - modifiers: arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + modifiers: modifiers, flags: arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_ARROW, }) ), @@ -55,7 +63,7 @@ export class ComputedTranslator extends MethodTranslator implements InitializerC false ), undefined, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE, + modifiers, false ); @@ -72,7 +80,9 @@ export class ComputedTranslator extends MethodTranslator implements InitializerC } generateComputedGet(newName: string): arkts.CallExpression { - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const thisValue: arkts.Expression = this.isStatic + ? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(this.classInfo.className), newName) + : generateThisBacking(newName, false, true); return generateGetOrSetCall(thisValue, GetSetTypes.GET); } } diff --git a/arkui-plugins/ui-plugins/property-translators/index.ts b/arkui-plugins/ui-plugins/property-translators/index.ts index 4aaf834360bdb4f165ef34f559842d698c002242..914006824c8ec1c4ffbcb63e1103f23147d53c3b 100644 --- a/arkui-plugins/ui-plugins/property-translators/index.ts +++ b/arkui-plugins/ui-plugins/property-translators/index.ts @@ -26,8 +26,8 @@ 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 { CustomComponentInfo, isStatic } from '../utils'; +import { StaticPropertyTranslator } from './staticProperty'; +import { CustomComponentInfo } from '../utils'; import { StoragePropInterfaceTranslator, StoragePropTranslator } from './storageProp'; import { ConsumeInterfaceTranslator, ConsumeTranslator } from './consume'; import { ProvideInterfaceTranslator, ProvideTranslator } from './provide'; @@ -66,8 +66,9 @@ export function classifyProperty( structInfo: CustomComponentInfo ): PropertyTranslator | undefined { if (!arkts.isClassProperty(property)) return undefined; - if (isStatic(property)) return new staticPropertyTranslator({ property, structInfo }); - + if (StaticPropertyTranslator.canBeStaticTranslate(property)) { + return new StaticPropertyTranslator({ property, structInfo }); + } let propertyTranslator: PropertyTranslator | undefined = undefined; propertyTranslator = classifyV1Property(property, structInfo); diff --git a/arkui-plugins/ui-plugins/property-translators/local.ts b/arkui-plugins/ui-plugins/property-translators/local.ts index 396497217a1c3b11f101cfe37a2fea018ea56111..84a76401ef8c85ece2e07179945637ce804efdb1 100644 --- a/arkui-plugins/ui-plugins/property-translators/local.ts +++ b/arkui-plugins/ui-plugins/property-translators/local.ts @@ -25,12 +25,25 @@ import { hasDecorator, collectStateManagementTypeImport, } from './utils'; -import { InterfacePropertyTranslator, InterfacePropertyTypes, PropertyTranslator } from './base'; +import { + InterfacePropertyTranslator, + InterfacePropertyTypes, + PropertyTranslator, + PropertyTranslatorOptions, +} from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { factory } from './factory'; +import { factory as UIFactory } from '../ui-factory'; import { PropertyCache } from './cache/propertyCache'; export class LocalTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { + private isStatic: boolean; + + constructor(options: PropertyTranslatorOptions) { + super(options); + this.isStatic = this.property.isStatic; + } + translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); @@ -39,18 +52,17 @@ export class LocalTranslator extends PropertyTranslator implements InitializerCo } cacheTranslatedInitializer(newName: string, originalName: string): void { - const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); - PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + if (!this.isStatic) { + const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName); + PropertyCache.getInstance().collectInitializeStruct(this.structInfo.name, [initializeStruct]); + } } translateWithoutInitializer(newName: string, originalName: string): arkts.AstNode[] { - const field: arkts.ClassProperty = factory.createOptionalClassProperty( - newName, - this.property, - StateManagementTypes.LOCAL_DECORATED, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE - ); - const thisValue: arkts.Expression = generateThisBacking(newName, false, true); + const field: arkts.ClassProperty = this.createPropertyField(newName, originalName); + const thisValue: arkts.Expression = this.isStatic + ? UIFactory.generateMemberExpression(arkts.factory.createIdentifier(this.structInfo.name), newName) + : generateThisBacking(newName, false, true); const thisGet: arkts.CallExpression = generateGetOrSetCall(thisValue, GetSetTypes.GET); const thisSet: arkts.ExpressionStatement = arkts.factory.createExpressionStatement( generateGetOrSetCall(thisValue, GetSetTypes.SET) @@ -61,12 +73,29 @@ export class LocalTranslator extends PropertyTranslator implements InitializerCo return [field, getter, setter]; } + createPropertyField(newName: string, originalName: string): arkts.ClassProperty { + return this.isStatic + ? arkts.factory.createClassProperty( + arkts.factory.createIdentifier(newName), + this.generateInitializeValue(originalName), + factory.createStageManagementType(StateManagementTypes.LOCAL_DECORATED, this.propertyType), + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC, + false + ) + : factory.createOptionalClassProperty( + newName, + this.property, + StateManagementTypes.LOCAL_DECORATED, + arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PRIVATE + ); + } + translateGetter( originalName: string, typeAnnotation: arkts.TypeNode | undefined, returnValue: arkts.Expression ): arkts.MethodDefinition { - return createGetter(originalName, typeAnnotation, returnValue); + return createGetter(originalName, typeAnnotation, returnValue, false, this.isStatic); } translateSetter( @@ -74,22 +103,32 @@ export class LocalTranslator extends PropertyTranslator implements InitializerCo typeAnnotation: arkts.TypeNode | undefined, statement: arkts.AstNode ): arkts.MethodDefinition { - return createSetter2(originalName, typeAnnotation, statement); + return createSetter2(originalName, typeAnnotation, statement, this.isStatic); } generateInitializeStruct(newName: string, originalName: string): arkts.AstNode { - const args: arkts.Expression[] = [ - arkts.factory.create1StringLiteral(originalName), - this.property.value ?? arkts.factory.createUndefinedLiteral(), - ]; collectStateManagementTypeImport(StateManagementTypes.LOCAL_DECORATED); const assign: arkts.AssignmentExpression = arkts.factory.createAssignmentExpression( generateThisBacking(newName), arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION, - factory.generateStateMgmtFactoryCall(StateManagementTypes.MAKE_LOCAL, this.propertyType, args, true) + this.generateInitializeValue(originalName) ); return arkts.factory.createExpressionStatement(assign); } + + generateInitializeValue(originalName: string): arkts.Expression { + const args: arkts.Expression[] = [ + arkts.factory.create1StringLiteral(originalName), + this.property.value ?? arkts.factory.createUndefinedLiteral(), + ]; + collectStateManagementTypeImport(StateManagementTypes.LOCAL_DECORATED); + return factory.generateStateMgmtFactoryCall( + this.isStatic ? StateManagementTypes.MAKE_STATIC_LOCAL : StateManagementTypes.MAKE_LOCAL, + this.propertyType, + args, + this.isStatic ? false : true + ); + } } export class LocalInterfaceTranslator extends InterfacePropertyTranslator { diff --git a/arkui-plugins/ui-plugins/property-translators/staticProperty.ts b/arkui-plugins/ui-plugins/property-translators/staticProperty.ts index 12e9535c5eebcbfcafca53beb45df1dcc221a1b0..c36c9781adf7de7d64955654f23554e7a1926b5a 100644 --- a/arkui-plugins/ui-plugins/property-translators/staticProperty.ts +++ b/arkui-plugins/ui-plugins/property-translators/staticProperty.ts @@ -15,12 +15,14 @@ import * as arkts from '@koalaui/libarkts'; -import { createGetter, createSetter } from './utils'; +import { createGetter, createSetter, hasDecorator } from './utils'; import { PropertyTranslator } from './base'; import { GetterSetter, InitializerConstructor } from './types'; import { backingField, expectName } from '../../common/arkts-utils'; +import { isStatic } from '../../ui-plugins/utils'; +import { DecoratorNames } from '../../common/predefines'; -export class staticPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { +export class StaticPropertyTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter { translateMember(): arkts.AstNode[] { const originalName: string = expectName(this.property.key); const newName: string = backingField(originalName); @@ -49,4 +51,8 @@ export class staticPropertyTranslator extends PropertyTranslator implements Init const right: arkts.Identifier = arkts.factory.createIdentifier('value'); return createSetter(originalName, typeAnnotation, left, right); } + + static canBeStaticTranslate(node: arkts.ClassProperty): boolean { + return isStatic(node) && !hasDecorator(node, DecoratorNames.LOCAL); + } } diff --git a/arkui-plugins/ui-plugins/property-translators/utils.ts b/arkui-plugins/ui-plugins/property-translators/utils.ts index 6a7abfbe8b22ab541daf072b7404b524f2e4d772..719605743ebc0ff0d617d22058c3513cf4977f43 100644 --- a/arkui-plugins/ui-plugins/property-translators/utils.ts +++ b/arkui-plugins/ui-plugins/property-translators/utils.ts @@ -176,24 +176,28 @@ export function createGetter( name: string, type: arkts.TypeNode | undefined, returns: arkts.Expression, - needMemo: boolean = false + needMemo: boolean = false, + isStatic: boolean = false ): arkts.MethodDefinition { const returnType: arkts.TypeNode | undefined = type?.clone(); if (needMemo && findCanAddMemoFromTypeAnnotation(returnType)) { addMemoAnnotation(returnType); } const body = arkts.factory.createBlock([arkts.factory.createReturnStatement(returns)]); + const modifiers = isStatic + ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC + : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; const scriptFunction = arkts.factory.createScriptFunction( body, arkts.FunctionSignature.createFunctionSignature(undefined, [], returnType, false), arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_GETTER, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + modifiers ); return arkts.factory.createMethodDefinition( arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET, arkts.factory.createIdentifier(name), scriptFunction, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + modifiers, false ); } @@ -240,25 +244,29 @@ export function createSetter( export function createSetter2( name: string, type: arkts.TypeNode | undefined, - statement: arkts.AstNode + statement: arkts.AstNode, + isStatic: boolean = false ): arkts.MethodDefinition { const body = arkts.factory.createBlock([statement]); const param: arkts.ETSParameterExpression = arkts.factory.createParameterDeclaration( arkts.factory.createIdentifier('value', type?.clone()), undefined ); + const modifiers = isStatic + ? arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_STATIC + : arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC; const scriptFunction = arkts.factory.createScriptFunction( body, arkts.FunctionSignature.createFunctionSignature(undefined, [param], undefined, false), arkts.Es2pandaScriptFunctionFlags.SCRIPT_FUNCTION_FLAGS_SETTER, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC + modifiers ); return arkts.factory.createMethodDefinition( arkts.Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_SET, arkts.factory.createIdentifier(name), scriptFunction, - arkts.Es2pandaModifierFlags.MODIFIER_FLAGS_PUBLIC, + modifiers, false ); }