• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-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 { global } from '../static/global';
17import { isNumber, throwError, getEnumName } from '../../utils';
18import { KNativePointer, KInt, nullptr, withStringResult } from '@koalaui/interop';
19import { passNode, passString, unpackNodeArray, unpackNonNullableNode } from './private';
20import { isFunctionDeclaration, isMemberExpression, isMethodDefinition, isNumberLiteral } from '../factory/nodeTests';
21import {
22    Es2pandaContextState,
23    Es2pandaMethodDefinitionKind,
24    Es2pandaModifierFlags,
25} from '../../generated/Es2pandaEnums';
26import type { AstNode } from '../peers/AstNode';
27import {
28    ClassDefinition,
29    ClassProperty,
30    ETSImportDeclaration,
31    ImportSpecifier,
32    isClassDefinition,
33    isIdentifier,
34    isObjectExpression,
35    isProperty,
36    isScriptFunction,
37    isTSInterfaceDeclaration,
38    Property,
39    type AnnotationUsage,
40} from '../../generated';
41import { Program } from '../peers/Program';
42import { clearNodeCache } from '../class-by-peer';
43import { SourcePosition } from '../peers/SourcePosition';
44import { MemberExpression } from '../to-be-generated/MemberExpression';
45
46export function proceedToState(state: Es2pandaContextState, forceDtsEmit = false): void {
47    console.log('[TS WRAPPER] PROCEED TO STATE: ', getEnumName(Es2pandaContextState, state));
48    if (global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR) {
49        processErrorState(state, forceDtsEmit);
50    }
51    if (state <= global.es2panda._ContextState(global.context)) {
52        console.log('[TS WRAPPER] PROCEED TO STATE: SKIPPING');
53        return;
54    }
55    clearNodeCache();
56    global.es2panda._ProceedToState(global.context, state);
57    processErrorState(state, forceDtsEmit);
58}
59
60function processErrorState(state: Es2pandaContextState, forceDtsEmit = false): void {
61    try {
62        if (
63            global.es2panda._ContextState(global.context) === Es2pandaContextState.ES2PANDA_STATE_ERROR &&
64            !forceDtsEmit
65        ) {
66            const errorMessage = withStringResult(global.es2panda._ContextErrorMessage(global.context));
67            if (errorMessage === undefined) {
68                throwError(`Could not get ContextErrorMessage`);
69            }
70            const allErrorMessages = withStringResult(global.es2panda._GetAllErrorMessages(global.context));
71            if (allErrorMessages === undefined) {
72                throwError(`Could not get AllErrorMessages`);
73            }
74            throwError([`Failed to proceed to ${Es2pandaContextState[state]}`, errorMessage, allErrorMessages].join(`\n`));
75        }
76    } catch (e) {
77        global.es2panda._DestroyContext(global.context);
78        throw e;
79    }
80}
81
82export function startChecker(): boolean {
83    return global.es2panda._CheckerStartChecker(global.context);
84}
85
86export function recheckSubtree(node: AstNode): void {
87    global.es2panda._AstNodeRecheck(global.context, node.peer);
88}
89
90export function rebindSubtree(node: AstNode): void {
91    global.es2panda._AstNodeRebind(global.context, node.peer);
92}
93
94export function getDecl(node: AstNode): AstNode | undefined {
95    if (isMemberExpression(node)) {
96        return getDeclFromArrayOrObjectMember(node);
97    }
98    if (isObjectExpression(node)) {
99        return getPeerObjectDecl(passNode(node));
100    }
101    const decl = getPeerDecl(passNode(node));
102    if (!!decl) {
103        return decl;
104    }
105    if (isProperty(node.parent)) {
106        return getDeclFromProperty(node.parent);
107    }
108    return undefined;
109}
110
111function getDeclFromProperty(node: Property): AstNode | undefined {
112    if (!node.key) {
113        return undefined;
114    }
115    if (!isObjectExpression(node.parent)) {
116        return getPeerDecl(passNode(node.key));
117    }
118    return getDeclFromObjectExpressionProperty(node);
119}
120
121function getDeclFromObjectExpressionProperty(node: Property): AstNode | undefined {
122    const declNode = getPeerObjectDecl(passNode(node.parent));
123    if (!declNode || !node.key || !isIdentifier(node.key)) {
124        return undefined;
125    }
126    let body: readonly AstNode[] = [];
127    if (isClassDefinition(declNode)) {
128        body = declNode.body;
129    } else if (isTSInterfaceDeclaration(declNode)) {
130        body = declNode.body?.body ?? [];
131    }
132    return body.find(
133        (statement) =>
134            isMethodDefinition(statement) &&
135            statement.kind === Es2pandaMethodDefinitionKind.METHOD_DEFINITION_KIND_GET &&
136            !!statement.name &&
137            !!node.key &&
138            isIdentifier(node.key) &&
139            statement.name.name === node.key.name
140    );
141}
142
143function getDeclFromArrayOrObjectMember(node: MemberExpression): AstNode | undefined {
144    if (isNumberLiteral(node.property)) {
145        return getDecl(node.object);
146    }
147    return getDecl(node.property);
148}
149
150export function getPeerDecl(peer: KNativePointer): AstNode | undefined {
151    const decl = global.es2panda._DeclarationFromIdentifier(global.context, peer);
152    if (decl === nullptr) {
153        return undefined;
154    }
155    return unpackNonNullableNode(decl);
156}
157
158export function getPeerObjectDecl(peer: KNativePointer): AstNode | undefined {
159    const decl = global.es2panda._ClassVariableDeclaration(global.context, peer);
160    if (decl === nullptr) {
161        return undefined;
162    }
163    return unpackNonNullableNode(decl);
164}
165
166export function getAnnotations(node: AstNode): readonly AnnotationUsage[] {
167    if (!isFunctionDeclaration(node) && !isScriptFunction(node) && !isClassDefinition(node)) {
168        throwError('for now annotations allowed only for: functionDeclaration, scriptFunction, classDefinition');
169    }
170    return unpackNodeArray(global.es2panda._AnnotationAllowedAnnotations(global.context, node.peer, nullptr));
171}
172
173export function getOriginalNode(node: AstNode): AstNode {
174    if (node === undefined) {
175        // TODO: fix this
176        throwError('there is no arkts pair of ts node (unable to getOriginalNode)');
177    }
178    if (node.originalPeer === nullptr) {
179        return node;
180    }
181    return unpackNonNullableNode(node.originalPeer);
182}
183
184export function getFileName(): string {
185    return global.filePath;
186}
187
188export function classDefinitionSetFromStructModifier(node: ClassDefinition): void {
189    global.es2panda._ClassDefinitionSetFromStructModifier(global.context, node.peer);
190}
191
192export function classDefinitionIsFromStructConst(node: ClassDefinition): boolean {
193    return global.es2panda._ClassDefinitionIsFromStructConst(global.context, node.peer);
194}
195
196export function ImportSpecifierSetRemovable(node: ImportSpecifier): void {
197    global.es2panda._ImportSpecifierSetRemovable(global.context, node.peer);
198}
199
200export function ImportSpecifierIsRemovableConst(node: ImportSpecifier): boolean {
201    return global.es2panda._ImportSpecifierIsRemovableConst(global.context, node.peer);
202}
203
204// TODO: It seems like Definition overrides AstNode  modifiers
205// with it's own modifiers which is completely unrelated set of flags.
206// Use this function if you need
207// the language level modifiers: public, declare, export, etc.
208export function classDefinitionFlags(node: ClassDefinition): Es2pandaModifierFlags {
209    return global.generatedEs2panda._AstNodeModifiers(global.context, node.peer);
210}
211
212// TODO: Import statements should be inserted to the statements
213export function importDeclarationInsert(node: ETSImportDeclaration, program: Program): void {
214    global.es2panda._InsertETSImportDeclarationAndParse(global.context, program.peer, node.peer);
215}
216
217export function hasModifierFlag(node: AstNode, flag: Es2pandaModifierFlags): boolean {
218    if (!node) return false;
219
220    let modifiers;
221    if (isClassDefinition(node)) {
222        modifiers = classDefinitionFlags(node);
223    } else {
224        modifiers = node.modifiers;
225    }
226    return (modifiers & flag) === flag;
227}
228
229// TODO: ClassProperty's optional flag is set by AstNode's modifiers flags.
230export function classPropertySetOptional(node: ClassProperty, value: boolean): ClassProperty {
231    if (value) {
232        node.modifiers |= Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL;
233    } else {
234        node.modifiers &= Es2pandaModifierFlags.MODIFIER_FLAGS_OPTIONAL;
235    }
236    return node;
237}
238
239export function modifiersToString(modifiers: Es2pandaModifierFlags): string {
240    return Object.values(Es2pandaModifierFlags)
241        .filter(isNumber)
242        .map((it) => {
243            console.log(it.valueOf(), Es2pandaModifierFlags[it], modifiers.valueOf() & it);
244            return (modifiers.valueOf() & it) === it ? Es2pandaModifierFlags[it] : '';
245        })
246        .join(' ');
247}
248export function destroyConfig(config: KNativePointer): void {
249    global.es2panda._DestroyConfig(config);
250    global.resetConfig();
251}
252
253export function setAllParents(ast: AstNode) {
254    global.es2panda._AstNodeUpdateAll(global.context, ast.peer);
255}
256
257export function generateTsDeclarationsFromContext(
258  outputDeclEts: string,
259  outputEts: string,
260  exportAll: boolean,
261  recordFile: string
262): KInt {
263  return global.es2panda._GenerateTsDeclarationsFromContext(
264    global.context,
265    passString(outputDeclEts),
266    passString(outputEts),
267    exportAll,
268    passString(recordFile)
269  );
270}
271
272export function isDefaultAccessModifierClassProperty(property: ClassProperty): boolean {
273    return global.es2panda._ClassPropertyIsDefaultAccessModifierConst(global.context, property.peer);
274}
275
276export function getStartPosition(node: AstNode): SourcePosition {
277    return new SourcePosition(global.es2panda._AstNodeStartConst(global.context, node.peer));
278}
279
280export function getEndPosition(node: AstNode): SourcePosition {
281    return new SourcePosition(global.es2panda._AstNodeEndConst(global.context, node.peer));
282}
283