• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as arkts from '@koalaui/libarkts';
17
18import { DecoratorNames, generateToRecord } from './utils';
19import { PropertyTranslator } from './base';
20import { GetterSetter, InitializerConstructor } from './types';
21import { backingField, expectName } from '../../common/arkts-utils';
22
23function getLocalStorageporpValueStr(node: arkts.AstNode): string | undefined {
24    if (!arkts.isClassProperty(node) || !node.value) return undefined;
25
26    return arkts.isStringLiteral(node.value) ? node.value.str : undefined;
27}
28function getLocalStorageporpAnnotationValue(anno: arkts.AnnotationUsage): string | undefined {
29    const isLocalStorageporpAnnotation: boolean =
30        !!anno.expr && arkts.isIdentifier(anno.expr) && anno.expr.name === DecoratorNames.LOCAL_STORAGE_PROP;
31
32    if (isLocalStorageporpAnnotation && anno.properties.length === 1) {
33        return getLocalStorageporpValueStr(anno.properties.at(0)!);
34    }
35    return undefined;
36}
37
38function getLocalStorageporpValueInAnnotation(node: arkts.ClassProperty): string | undefined {
39    const annotations: readonly arkts.AnnotationUsage[] = node.annotations;
40
41    for (let i = 0; i < annotations.length; i++) {
42        const anno: arkts.AnnotationUsage = annotations[i];
43        const str: string | undefined = getLocalStorageporpAnnotationValue(anno);
44        if (!!str) {
45            return str;
46        }
47    }
48
49    return undefined;
50}
51
52export class LocalStoragePropTranslator extends PropertyTranslator implements InitializerConstructor, GetterSetter {
53    translateMember(): arkts.AstNode[] {
54        const originalName: string = expectName(this.property.key);
55        const newName: string = backingField(originalName);
56
57        this.cacheTranslatedInitializer(newName, originalName); // TODO: need to release cache after some point...
58        return this.translateWithoutInitializer(newName, originalName);
59    }
60
61    cacheTranslatedInitializer(newName: string, originalName: string): void {
62        const currentStructInfo: arkts.StructInfo = arkts.GlobalInfo.getInfoInstance().getStructInfo(this.structName);
63        const initializeStruct: arkts.AstNode = this.generateInitializeStruct(newName, originalName);
64        const updateStruct: arkts.AstNode = this.generateUpdateStruct(newName, originalName);
65        currentStructInfo.initializeBody.push(initializeStruct);
66        currentStructInfo.updateBody.push(updateStruct);
67
68        if (currentStructInfo.isReusable) {
69            const toRecord = generateToRecord(newName, originalName);
70            currentStructInfo.toRecordBody.push(toRecord);
71        }
72
73        arkts.GlobalInfo.getInfoInstance().setStructInfo(this.structName, currentStructInfo);
74    }
75
76    generateInitializeStruct(newName: string, originalName: string): arkts.AstNode {
77        const localStorageporpValueStr: string | undefined = getLocalStorageporpValueInAnnotation(this.property);
78        if (!localStorageporpValueStr) {
79            throw new Error('LocalStorageProp required only one value!!'); // TODO: replace this with proper error message.
80        }
81        const insideMember = arkts.factory.createMemberExpression(
82            arkts.factory.createThisExpression(),
83            arkts.factory.createIdentifier('_entry_local_storage_'),
84            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
85            false,
86            false
87        );
88        const binaryItem = arkts.factory.createCallExpression(
89            arkts.factory.createIdentifier('StorageLinkState'),
90            this.property.typeAnnotation ? [this.property.typeAnnotation] : [],
91            [
92                insideMember,
93                arkts.factory.createStringLiteral(localStorageporpValueStr),
94                this.property.value ?? arkts.factory.createUndefinedLiteral(),
95            ]
96        );
97        const call = arkts.factory.createCallExpression(
98            arkts.factory.createIdentifier('propState'),
99            this.property.typeAnnotation ? [this.property.typeAnnotation] : [],
100            [
101                arkts.factory.createMemberExpression(
102                    binaryItem,
103                    arkts.factory.createIdentifier('value'),
104                    arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
105                    false,
106                    false
107                ),
108            ]
109        );
110        return arkts.factory.createAssignmentExpression(
111            arkts.factory.createMemberExpression(
112                arkts.factory.createThisExpression(),
113                arkts.factory.createIdentifier(newName),
114                arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
115                false,
116                false
117            ),
118            arkts.Es2pandaTokenType.TOKEN_TYPE_PUNCTUATOR_SUBSTITUTION,
119            call
120        );
121    }
122
123    generateUpdateStruct(newName: string, originalName: string): arkts.AstNode {
124        const localStorageporpValueStr: string | undefined = getLocalStorageporpValueInAnnotation(this.property);
125        if (!localStorageporpValueStr) {
126            throw new Error('StorageLink required only one value!!'); // TODO: replace this with proper error message.
127        }
128
129        const StorageLinkStateValue = arkts.factory.createMemberExpression(
130            arkts.factory.createCallExpression(
131                arkts.factory.createIdentifier('StorageLinkState'),
132                this.property.typeAnnotation ? [this.property.typeAnnotation] : [],
133                [
134                    arkts.factory.createMemberExpression(
135                        arkts.factory.createThisExpression(),
136                        arkts.factory.createIdentifier('_entry_local_storage_'),
137                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
138                        false,
139                        false
140                    ),
141                    arkts.factory.createStringLiteral(localStorageporpValueStr),
142                    this.property.value ?? arkts.factory.createUndefinedLiteral(),
143                ]
144            ),
145            arkts.factory.createIdentifier('value'),
146            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
147            false,
148            false
149        );
150
151        const test = arkts.factory.createMemberExpression(
152            arkts.factory.createThisExpression(),
153            arkts.factory.createIdentifier(newName),
154            arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
155            false,
156            false
157        );
158
159        const consequent = arkts.BlockStatement.createBlockStatement([
160            arkts.factory.createExpressionStatement(
161                arkts.factory.createCallExpression(
162                    arkts.factory.createMemberExpression(
163                        arkts.factory.createTSNonNullExpression(test),
164                        arkts.factory.createIdentifier('update'),
165                        arkts.Es2pandaMemberExpressionKind.MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS,
166                        false,
167                        false
168                    ),
169                    undefined,
170                    [StorageLinkStateValue]
171                )
172            ),
173        ]);
174
175        return arkts.factory.createExpressionStatement(arkts.factory.createIfStatement(test, consequent));
176    }
177}
178