• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 
16 #include "declgenEts2Ts.h"
17 
18 #include "ir/base/classProperty.h"
19 #include "ir/base/methodDefinition.h"
20 #include "ir/base/scriptFunction.h"
21 #include "ir/ets/etsImportDeclaration.h"
22 #include "ir/expressions/identifier.h"
23 #include "ir/expressions/literals/numberLiteral.h"
24 #include "ir/module/importSpecifier.h"
25 #include "ir/statements/blockStatement.h"
26 #include "ir/statements/classDeclaration.h"
27 #include "ir/ts/tsEnumMember.h"
28 #include "ir/ts/tsInterfaceBody.h"
29 #include "ir/ts/tsTypeAliasDeclaration.h"
30 #include "ir/ts/tsTypeParameter.h"
31 
32 #define DEBUG_PRINT 0
33 
34 namespace ark::es2panda::declgen_ets2ts {
35 
DebugPrint(const std::string & msg)36 static void DebugPrint([[maybe_unused]] const std::string &msg)
37 {
38 #if DEBUG_PRINT
39     std::cerr << msg << std::endl;
40 #endif
41 }
42 
Warning(const std::string & msg)43 static void Warning(const std::string &msg)
44 {
45     std::cerr << "Warning declgen ets2ts: " << msg << std::endl;
46 }
47 
Generate()48 void TSDeclGen::Generate()
49 {
50     std::stringstream license;
51     license << "/*\n";
52     license << " * Copyright (c) 2023-2024 Huawei Device Co., Ltd.\n";
53     license << " * Licensed under the Apache License, Version 2.0 (the \"License\");\n";
54     license << " * you may not use this file except in compliance with the License.\n";
55     license << " * You may obtain a copy of the License at\n";
56     license << " *\n";
57     license << " *     http://www.apache.org/licenses/LICENSE-2.0\n";
58     license << " *\n";
59     license << " * Unless required by applicable law or agreed to in writing, software\n";
60     license << " * distributed under the License is distributed on an \"AS IS\" BASIS,\n";
61     license << " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n";
62     license << " * See the License for the specific language governing permissions and\n";
63     license << " * limitations under the License.\n";
64     license << " */\n\n";
65     Out(license.str());
66     Out("declare const exports: any;");
67     OutEndl();
68     Out("let ETSGLOBAL: any = (globalThis as any).Panda.getClass('LETSGLOBAL;');");
69     OutEndl(2U);
70 
71     for (auto *globalStatement : program_->Ast()->Statements()) {
72         ResetState();
73         if (globalStatement->IsETSImportDeclaration()) {
74             GenImportDeclaration(globalStatement->AsETSImportDeclaration());
75         } else if (globalStatement->IsTSEnumDeclaration()) {
76             GenEnumDeclaration(globalStatement->AsTSEnumDeclaration());
77         } else if (globalStatement->IsClassDeclaration()) {
78             // The classes generated for enums starts with '#' but those are invalid names and
79             // not requred for the ts code
80             if (globalStatement->AsClassDeclaration()->Definition()->Ident()->Name().Mutf8().find('#') ==
81                 std::string::npos) {
82                 GenClassDeclaration(globalStatement->AsClassDeclaration());
83             }
84         } else if (globalStatement->IsTSInterfaceDeclaration()) {
85             GenInterfaceDeclaration(globalStatement->AsTSInterfaceDeclaration());
86         } else if (globalStatement->IsTSTypeAliasDeclaration()) {
87             GenTypeAliasDeclaration(globalStatement->AsTSTypeAliasDeclaration());
88         }
89     }
90 }
91 
92 template <class T, class CB>
GenSeparated(const T & container,const CB & cb,const char * separator)93 void TSDeclGen::GenSeparated(const T &container, const CB &cb, const char *separator)
94 {
95     if (container.empty()) {
96         return;
97     }
98 
99     cb(container[0]);
100     for (std::size_t i = 1; i < container.size(); ++i) {
101         Out(separator);
102         cb(container[i]);
103     }
104 }
105 
ThrowError(const std::string_view message,const lexer::SourcePosition & pos=lexer::SourcePosition ())106 void TSDeclGen::ThrowError(const std::string_view message, const lexer::SourcePosition &pos = lexer::SourcePosition())
107 {
108     lexer::LineIndex index(program_->SourceCode());
109     const lexer::SourceLocation loc = index.GetLocation(pos);
110 
111     throw Error {ErrorType::GENERIC, program_->SourceFilePath().Utf8(), "declgen ets2ts: " + std::string(message),
112                  loc.line, loc.col};
113 }
114 
GetKeyIdent(const ir::Expression * key)115 const ir::Identifier *TSDeclGen::GetKeyIdent(const ir::Expression *key)
116 {
117     if (!key->IsIdentifier()) {
118         ThrowError("Not identifier keys are not supported", key->Start());
119     }
120 
121     return key->AsIdentifier();
122 }
123 
GetDebugTypeName(const checker::Type * checkerType)124 static char const *GetDebugTypeName(const checker::Type *checkerType)
125 {
126 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
127 #define TYPE_CHECKS(type_flag, typeName)                                                    \
128     if (checkerType->Is##typeName()) {                                                      \
129         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
130         return #typeName;                                                                   \
131     }
132     TYPE_MAPPING(TYPE_CHECKS)
133 #undef TYPE_CHECKS
134     return "unknown type";
135 }
136 
GenType(const checker::Type * checkerType)137 void TSDeclGen::GenType(const checker::Type *checkerType)
138 {
139     DebugPrint("  GenType: ");
140 #if DEBUG_PRINT
141     const auto var_name = checkerType->Variable() == nullptr ? "" : checkerType->Variable()->Name().Mutf8();
142     DebugPrint(std::string("  Converting type: ") + GetDebugTypeName(checkerType) + " (" + var_name + ")");
143 #endif
144 
145     if (checkerType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
146         Out("number");
147         return;
148     }
149     if (checkerType->HasTypeFlag(checker::TypeFlag::FUNCTION)) {
150         GenFunctionType(checkerType->AsETSFunctionType());
151         return;
152     }
153 
154     switch (checker::ETSChecker::ETSType(checkerType)) {
155         case checker::TypeFlag::ETS_VOID:
156         case checker::TypeFlag::ETS_NULL:
157         case checker::TypeFlag::ETS_UNDEFINED:
158         case checker::TypeFlag::ETS_BOOLEAN:
159         case checker::TypeFlag::ETS_TYPE_PARAMETER:
160         case checker::TypeFlag::ETS_NONNULLISH:
161         case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER:
162         case checker::TypeFlag::ETS_NEVER:
163         case checker::TypeFlag::ETS_READONLY:
164         case checker::TypeFlag::ETS_INT_ENUM:
165             Out(checkerType->ToString());
166             return;
167         case checker::TypeFlag::ETS_OBJECT:
168         case checker::TypeFlag::ETS_DYNAMIC_TYPE:
169             GenObjectType(checkerType->AsETSObjectType());
170             return;
171         case checker::TypeFlag::ETS_ARRAY:
172             GenType(checkerType->AsETSArrayType()->ElementType());
173             Out("[]");
174             return;
175         case checker::TypeFlag::ETS_UNION:
176             GenUnionType(checkerType->AsETSUnionType());
177             return;
178         default:
179             ThrowError(std::string("Unsupported type: '") + GetDebugTypeName(checkerType));
180     }
181 }
182 
GenLiteral(const ir::Literal * literal)183 void TSDeclGen::GenLiteral(const ir::Literal *literal)
184 {
185     if (!literal->IsNumberLiteral()) {
186         ThrowError("Unsupported literal type", literal->Start());
187     }
188 
189     const auto number = literal->AsNumberLiteral()->Number();
190     if (number.IsInt()) {
191         Out(std::to_string(number.GetInt()));
192         return;
193     }
194     if (number.IsLong()) {
195         Out(std::to_string(number.GetLong()));
196         return;
197     }
198     if (number.IsFloat()) {
199         Out(std::to_string(number.GetFloat()));
200         return;
201     }
202     if (number.IsDouble()) {
203         Out(std::to_string(number.GetDouble()));
204         return;
205     }
206 
207     ThrowError("Unexpected number literal type", literal->Start());
208 }
209 
GenFunctionBody(const ir::MethodDefinition * methodDef,const checker::Signature * sig,const bool isConstructor,const bool isSetter)210 void TSDeclGen::GenFunctionBody(const ir::MethodDefinition *methodDef, const checker::Signature *sig,
211                                 const bool isConstructor, const bool isSetter)
212 {
213     if (isConstructor) {
214         if (state_.super != nullptr) {
215             Out("{ super(...{} as (ConstructorParameters<typeof ");
216             GenType(state_.super->TsType());
217             Out(">)); }");
218         } else {
219             Out(" {}");
220         }
221     } else if (isSetter) {
222         Out(" {}");
223     } else {
224         Out(methodDef != nullptr ? ": " : " => ");
225         GenType(sig->ReturnType());
226         if (methodDef != nullptr && !state_.inInterface) {
227             Out(" { return {} as any; }");
228         }
229     }
230 }
231 
GenFunctionType(const checker::ETSFunctionType * etsFunctionType,const ir::MethodDefinition * methodDef)232 void TSDeclGen::GenFunctionType(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef)
233 {
234     const bool isConstructor = methodDef != nullptr ? methodDef->IsConstructor() : false;
235     const bool isSetter = methodDef != nullptr ? methodDef->Kind() == ir::MethodDefinitionKind::SET : false;
236     // CC-OFFNXT(G.FMT.14-CPP) project code style
237     const auto *sig = [this, methodDef, etsFunctionType]() -> const checker::Signature * {
238         if (methodDef != nullptr) {
239             return methodDef->Function()->Signature();
240         }
241         if (!etsFunctionType->IsETSArrowType()) {
242             const auto loc = methodDef != nullptr ? methodDef->Start() : lexer::SourcePosition();
243             ThrowError("Method overloads are not supported", loc);
244         }
245         return etsFunctionType->CallSignatures()[0];
246     }();
247 
248     const auto *func = sig->Function();
249     GenTypeParameters(func->TypeParams());
250     Out("(");
251 
252     GenSeparated(sig->Params(), [this](varbinder::LocalVariable *param) {
253         Out(param->Name());
254         const auto *paramType = param->TsType();
255 
256         if (param->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
257             Out("?");
258         }
259         Out(": ");
260         GenType(paramType);
261     });
262 
263     const auto *sigInfo = sig->GetSignatureInfo();
264     if (sigInfo->restVar != nullptr) {
265         if (!sig->Params().empty()) {
266             Out(", ");
267         }
268         Out("...", sigInfo->restVar->Name().Mutf8(), ": ");
269         GenType(sigInfo->restVar->TsType());
270     }
271 
272     Out(")");
273 
274     GenFunctionBody(methodDef, sig, isConstructor, isSetter);
275 }
276 
GenEnumType(const checker::ETSIntEnumType * enumType)277 void TSDeclGen::GenEnumType(const checker::ETSIntEnumType *enumType)
278 {
279     for (auto *member : enumType->GetMembers()) {
280         Out(INDENT);
281         if (!member->IsTSEnumMember()) {
282             ThrowError("Member of enum not of type TSEnumMember", member->Start());
283         }
284 
285         const auto *enumMember = member->AsTSEnumMember();
286         Out(GetKeyIdent(enumMember->Key())->Name().Mutf8());
287         const auto *init = enumMember->Init();
288         if (init != nullptr) {
289             Out(" = ");
290 
291             if (!init->IsLiteral()) {
292                 ThrowError("Only literal enum initializers are supported", member->Start());
293             }
294 
295             GenLiteral(init->AsLiteral());
296         }
297 
298         Out(",");
299         OutEndl();
300     }
301 }
302 
GenUnionType(const checker::ETSUnionType * unionType)303 void TSDeclGen::GenUnionType(const checker::ETSUnionType *unionType)
304 {
305     GenSeparated(
306         unionType->ConstituentTypes(), [this](checker::Type *arg) { GenType(arg); }, " | ");
307 }
308 
GenObjectType(const checker::ETSObjectType * objectType)309 void TSDeclGen::GenObjectType(const checker::ETSObjectType *objectType)
310 {
311     if (objectType->IsETSStringType()) {
312         Out("string");
313         return;
314     }
315     if (objectType->IsETSUnboxableObject()) {
316         Out("number");  // NOTE(ivagin): create precise builtin type
317         return;
318     }
319     if (objectType->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL)) {
320         const auto *invoke = objectType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(
321             checker::FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
322         ASSERT(invoke && invoke->TsType() && invoke->TsType()->IsETSFunctionType());
323         GenType(invoke->TsType());
324         return;
325     }
326     if (objectType->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC)) {
327         Out("any");
328         return;
329     }
330 
331     auto typeName = objectType->Name();
332     if (typeName.Empty()) {
333         Warning("Object type name is empty");
334         Out("any");
335     } else {
336         Out(typeName);
337     }
338 
339     const auto &typeArgs = objectType->TypeArguments();
340     if (!typeArgs.empty()) {
341         Out("<");
342         GenSeparated(typeArgs, [this](checker::Type *arg) { GenType(arg); });
343         Out(">");
344     }
345 }
346 
GenTypeParameters(const ir::TSTypeParameterDeclaration * typeParams)347 void TSDeclGen::GenTypeParameters(const ir::TSTypeParameterDeclaration *typeParams)
348 {
349     if (typeParams != nullptr) {
350         Out("<");
351         GenSeparated(typeParams->Params(), [this](ir::TSTypeParameter *param) {
352             Out(param->Name()->Name());
353             auto *constraint = param->Constraint();
354             if (constraint != nullptr) {
355                 Out(" extends ");
356                 GenType(constraint->GetType(checker_));
357             }
358         });
359         Out(">");
360     }
361 }
362 
GenExport(const ir::Identifier * symbol)363 void TSDeclGen::GenExport(const ir::Identifier *symbol)
364 {
365     const auto symbolName = symbol->Name().Mutf8();
366     Out("export {", symbolName, "};");
367     OutEndl();
368     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
369         Out("exports.", symbolName, " = ", symbolName, ";");
370     }
371     OutEndl();
372 }
373 
GenExport(const ir::Identifier * symbol,const std::string & alias)374 void TSDeclGen::GenExport(const ir::Identifier *symbol, const std::string &alias)
375 {
376     const auto symbolName = symbol->Name().Mutf8();
377     Out("export {", symbolName, " as ", alias, "};");
378     OutEndl();
379     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
380         Out("exports.", alias, " = ", symbolName, ";");
381     }
382     OutEndl();
383 }
384 
GenDefaultExport(const ir::Identifier * symbol)385 void TSDeclGen::GenDefaultExport(const ir::Identifier *symbol)
386 {
387     const auto symbolName = symbol->Name().Mutf8();
388     Out("export default ", symbolName, ";");
389     OutEndl();
390     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
391         Out("exports.default = ", symbolName, ";");
392     }
393     OutEndl();
394 }
395 
ExportIfNeeded(const ir::Identifier * symbol)396 void TSDeclGen::ExportIfNeeded(const ir::Identifier *symbol)
397 {
398     if (symbol->Parent()->IsExported()) {
399         GenExport(symbol);
400     }
401     if (symbol->Parent()->IsExportedType()) {
402         GenExport(symbol);
403     }
404     if (symbol->Parent()->IsDefaultExported()) {
405         GenDefaultExport(symbol);
406     }
407 }
408 
409 template <class T>
GenModifier(const T * node)410 void TSDeclGen::GenModifier(const T *node)
411 {
412     if (state_.inInterface) {
413         return;
414     }
415 
416     if (node->IsPrivate()) {
417         Out("private ");
418     }
419     if (node->IsProtected()) {
420         Out("protected ");
421     }
422     if (node->IsPublic()) {
423         Out("public ");
424     }
425     if (node->IsReadonly()) {
426         Out("readonly ");
427     }
428     if (node->IsStatic()) {
429         Out("static ");
430     }
431 }
432 
GenImportDeclaration(const ir::ETSImportDeclaration * importDeclaration)433 void TSDeclGen::GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration)
434 {
435     DebugPrint("GenImportDeclaration");
436     if (importDeclaration->IsPureDynamic()) {
437         return;
438     }
439 
440     const auto &specifiers = importDeclaration->Specifiers();
441     Out("import { ");
442     GenSeparated(specifiers, [this, &importDeclaration](ir::AstNode *specifier) {
443         if (!specifier->IsImportSpecifier()) {
444             ThrowError("Only import specifiers are supported", importDeclaration->Start());
445         }
446 
447         const auto local = specifier->AsImportSpecifier()->Local()->Name();
448         const auto imported = specifier->AsImportSpecifier()->Imported()->Name();
449         Out(local);
450         if (local != imported) {
451             ThrowError("Imports with local bindings are not supported", importDeclaration->Start());
452         }
453     });
454 
455     auto source = importDeclaration->Source()->Str().Mutf8();
456     Out(" } from \"", source, "\";");
457     OutEndl(2U);
458 }
459 
GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration * typeAlias)460 void TSDeclGen::GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)
461 {
462     const auto name = typeAlias->Id()->Name().Mutf8();
463     DebugPrint("GenTypeAliasDeclaration: " + name);
464     const auto *aliasedType = typeAlias->TypeAnnotation()->GetType(checker_);
465     Out("type ", name, " = ");
466     GenType(aliasedType);
467     Out(";");
468     OutEndl();
469 
470     ExportIfNeeded(typeAlias->Id());
471     OutEndl();
472 }
473 
GenEnumDeclaration(const ir::TSEnumDeclaration * enumDecl)474 void TSDeclGen::GenEnumDeclaration(const ir::TSEnumDeclaration *enumDecl)
475 {
476     const auto enumIdent = GetKeyIdent(enumDecl->Key());
477     const auto enumName = enumIdent->Name().Mutf8();
478     DebugPrint("GenEnumDeclaration: " + enumName);
479     Out("enum ", enumName, " {");
480     OutEndl();
481 
482     ASSERT(enumDecl->TsType()->IsETSIntEnumType());
483     GenEnumType(enumDecl->TsType()->AsETSIntEnumType());
484 
485     Out("}");
486     OutEndl();
487 
488     ExportIfNeeded(enumIdent);
489     OutEndl();
490 }
491 
GenInterfaceDeclaration(const ir::TSInterfaceDeclaration * interfaceDecl)492 void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)
493 {
494     state_.inInterface = true;
495     const auto interfaceName = interfaceDecl->Id()->Name().Mutf8();
496     DebugPrint("GenInterfaceDeclaration: " + interfaceName);
497     if (interfaceName.find("$partial") != std::string::npos) {
498         return;
499     }
500     Out("interface ", interfaceName);
501 
502     GenTypeParameters(interfaceDecl->TypeParams());
503 
504     Out(" {");
505     OutEndl();
506 
507     for (auto *prop : interfaceDecl->Body()->Body()) {
508         if (prop->IsMethodDefinition()) {
509             GenMethodDeclaration(prop->AsMethodDefinition());
510             for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
511                 GenMethodDeclaration(methodDef);
512             }
513         }
514         if (prop->IsClassProperty()) {
515             GenPropDeclaration(prop->AsClassProperty());
516         }
517     }
518 
519     Out("}");
520     OutEndl();
521 
522     ExportIfNeeded(interfaceDecl->Id());
523     OutEndl();
524 }
525 
GenClassDeclaration(const ir::ClassDeclaration * classDecl)526 void TSDeclGen::GenClassDeclaration(const ir::ClassDeclaration *classDecl)
527 {
528     const auto *classDef = classDecl->Definition();
529     std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";";
530     std::replace(classDescriptor.begin(), classDescriptor.end(), '.', '/');
531     state_.currentClassDescriptor = classDescriptor;
532     const auto className = classDef->Ident()->Name().Mutf8();
533     state_.inGlobalClass = classDef->IsGlobal();
534 
535     DebugPrint("GenClassDeclaration: " + className);
536 
537     if (className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS ||
538         className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos)) {
539         return;
540     }
541 
542     if (!state_.inGlobalClass) {
543         Out("class ", className);
544         GenTypeParameters(classDef->TypeParams());
545 
546         const auto *super = classDef->Super();
547         state_.super = super;
548         if (super != nullptr) {
549             Out(" extends ");
550             GenType(super->TsType());
551         }
552 
553         const auto &interfaces = classDef->TsType()->AsETSObjectType()->Interfaces();
554         if (!interfaces.empty()) {
555             Out(" implements ");
556             ASSERT(classDef->TsType()->IsETSObjectType());
557             GenSeparated(interfaces, [this](checker::ETSObjectType *interface) { GenType(interface); });
558         }
559 
560         Out(" {");
561         OutEndl();
562     }
563 
564     for (const auto *prop : classDef->Body()) {
565         if (prop->IsMethodDefinition()) {
566             GenMethodDeclaration(prop->AsMethodDefinition());
567             for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
568                 GenMethodDeclaration(methodDef);
569             }
570         } else if (prop->IsClassProperty()) {
571             GenPropDeclaration(prop->AsClassProperty());
572         }
573     }
574 
575     if (!state_.inGlobalClass) {
576         Out("};");
577         OutEndl();
578         Out("(", className, " as any) = (globalThis as any).Panda.getClass('", state_.currentClassDescriptor, "');");
579         OutEndl();
580         ExportIfNeeded(classDef->Ident());
581         OutEndl();
582     }
583 }
584 
GenMethodDeclaration(const ir::MethodDefinition * methodDef)585 void TSDeclGen::GenMethodDeclaration(const ir::MethodDefinition *methodDef)
586 {
587     const auto methodIdent = GetKeyIdent(methodDef->Key());
588     const auto methodName = methodIdent->Name().Mutf8();
589     if (methodName.find('#') != std::string::npos) {
590         return;
591     }
592 
593     if (state_.inGlobalClass) {
594         Out("function ");
595     } else {
596         Out(INDENT);
597         GenModifier(methodDef);
598     }
599 
600     if (methodDef->Kind() == ir::MethodDefinitionKind::GET) {
601         Out("get ");
602     }
603     if (methodDef->Kind() == ir::MethodDefinitionKind::SET) {
604         Out("set ");
605     }
606 
607     DebugPrint("  GenMethodDeclaration: " + methodName);
608     Out(methodName);
609 
610     if (methodDef->TsType() == nullptr) {
611         Warning("Untyped method encountered: " + methodName);
612         Out(": any");
613     } else {
614         GenFunctionType(methodDef->TsType()->AsETSFunctionType(), methodDef);
615     }
616 
617     Out(";");
618     OutEndl();
619 
620     if (state_.inGlobalClass) {
621         Out("(", methodName, " as any) = ETSGLOBAL.", methodName, ";");
622         OutEndl();
623         ExportIfNeeded(methodIdent);
624         if (methodName == compiler::Signatures::INIT_METHOD) {
625             Out(methodName, "();");
626         }
627         OutEndl(2U);
628     }
629 }
630 
GenPropDeclaration(const ir::ClassProperty * classProp)631 void TSDeclGen::GenPropDeclaration(const ir::ClassProperty *classProp)
632 {
633     if (state_.inGlobalClass) {
634         GenGlobalVarDeclaration(classProp);
635         return;
636     }
637 
638     const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
639     DebugPrint("  GenPropDeclaration: " + propName);
640 
641     Out(INDENT);
642     GenModifier(classProp);
643     Out(propName);
644 
645     Out(": ");
646     GenType(classProp->TsType());
647     if (!state_.inInterface) {
648         Out(" = {} as any");
649     }
650     Out(";");
651     OutEndl();
652 }
653 
GenGlobalVarDeclaration(const ir::ClassProperty * globalVar)654 void TSDeclGen::GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)
655 {
656     if (!globalVar->IsExported() && !globalVar->IsDefaultExported()) {
657         return;
658     }
659 
660     const auto symbol = GetKeyIdent(globalVar->Key());
661     const auto varName = symbol->Name().Mutf8();
662     DebugPrint("GenGlobalVarDeclaration: " + varName);
663     if (!globalVar->IsConst()) {
664         Warning("Not constant global variables are not supported, variable \"" + varName + "\" was skipped");
665         return;
666     }
667 
668     Out("const ", varName, ": ");
669     GenType(globalVar->TsType());
670     Out(" = ETSGLOBAL.", varName, ';');
671     OutEndl();
672 
673     GenExport(symbol);
674     OutEndl();
675 }
676 
GenerateTsDeclarations(checker::ETSChecker * checker,const ark::es2panda::parser::Program * program,const std::string & outPath)677 bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program,
678                             const std::string &outPath)
679 {
680     TSDeclGen declBuilder(checker, program);
681     declBuilder.Generate();
682 
683     std::ofstream outStream(outPath);
684     if (outStream.fail()) {
685         std::cerr << "Failed to open file: " << outPath << std::endl;
686         return false;
687     }
688 
689     outStream << declBuilder.Output().str();
690     outStream.close();
691 
692     return true;
693 }
694 }  // namespace ark::es2panda::declgen_ets2ts
695