• 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         return #typeName;                \
130     }
131     TYPE_MAPPING(TYPE_CHECKS)
132 #undef TYPE_CHECKS
133     return "unknown type";
134 }
135 
GenType(const checker::Type * checkerType)136 void TSDeclGen::GenType(const checker::Type *checkerType)
137 {
138     DebugPrint("  GenType: ");
139 #if DEBUG_PRINT
140     const auto var_name = checkerType->Variable() == nullptr ? "" : checkerType->Variable()->Name().Mutf8();
141     DebugPrint(std::string("  Converting type: ") + GetDebugTypeName(checkerType) + " (" + var_name + ")");
142 #endif
143 
144     if (checkerType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
145         Out("number");
146         return;
147     }
148     if (checkerType->HasTypeFlag(checker::TypeFlag::FUNCTION)) {
149         GenFunctionType(checkerType->AsETSFunctionType());
150         return;
151     }
152 
153     switch (checker::ETSChecker::ETSType(checkerType)) {
154         case checker::TypeFlag::ETS_VOID:
155         case checker::TypeFlag::ETS_NULL:
156         case checker::TypeFlag::ETS_UNDEFINED:
157         case checker::TypeFlag::ETS_BOOLEAN:
158         case checker::TypeFlag::ETS_TYPE_PARAMETER:
159         case checker::TypeFlag::ETS_NONNULLISH:
160         case checker::TypeFlag::ETS_READONLY:
161         case checker::TypeFlag::ETS_INT_ENUM:
162             Out(checkerType->ToString());
163             return;
164         case checker::TypeFlag::ETS_OBJECT:
165         case checker::TypeFlag::ETS_DYNAMIC_TYPE:
166             GenObjectType(checkerType->AsETSObjectType());
167             return;
168         case checker::TypeFlag::ETS_ARRAY:
169             GenType(checkerType->AsETSArrayType()->ElementType());
170             Out("[]");
171             return;
172         case checker::TypeFlag::ETS_UNION:
173             GenUnionType(checkerType->AsETSUnionType());
174             return;
175         default:
176             ThrowError(std::string("Unsupported type: '") + GetDebugTypeName(checkerType));
177     }
178 }
179 
GenLiteral(const ir::Literal * literal)180 void TSDeclGen::GenLiteral(const ir::Literal *literal)
181 {
182     if (!literal->IsNumberLiteral()) {
183         ThrowError("Unsupported literal type", literal->Start());
184     }
185 
186     const auto number = literal->AsNumberLiteral()->Number();
187     if (number.IsInt()) {
188         Out(std::to_string(number.GetInt()));
189         return;
190     }
191     if (number.IsLong()) {
192         Out(std::to_string(number.GetLong()));
193         return;
194     }
195     if (number.IsFloat()) {
196         Out(std::to_string(number.GetFloat()));
197         return;
198     }
199     if (number.IsDouble()) {
200         Out(std::to_string(number.GetDouble()));
201         return;
202     }
203 
204     ThrowError("Unexpected number literal type", literal->Start());
205 }
206 
GenFunctionBody(const ir::MethodDefinition * methodDef,const checker::Signature * sig,const bool isConstructor,const bool isSetter)207 void TSDeclGen::GenFunctionBody(const ir::MethodDefinition *methodDef, const checker::Signature *sig,
208                                 const bool isConstructor, const bool isSetter)
209 {
210     if (isConstructor) {
211         if (state_.super != nullptr) {
212             Out("{ super(...{} as (ConstructorParameters<typeof ");
213             GenType(state_.super->TsType());
214             Out(">)); }");
215         } else {
216             Out(" {}");
217         }
218     } else if (isSetter) {
219         Out(" {}");
220     } else {
221         Out(methodDef != nullptr ? ": " : " => ");
222         GenType(sig->ReturnType());
223         if (methodDef != nullptr && !state_.inInterface) {
224             Out(" { return {} as any; }");
225         }
226     }
227 }
228 
GenFunctionType(const checker::ETSFunctionType * etsFunctionType,const ir::MethodDefinition * methodDef)229 void TSDeclGen::GenFunctionType(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef)
230 {
231     const bool isConstructor = methodDef != nullptr ? methodDef->IsConstructor() : false;
232     const bool isSetter = methodDef != nullptr ? methodDef->Kind() == ir::MethodDefinitionKind::SET : false;
233 
234     const auto *sig = [this, methodDef, etsFunctionType]() -> const checker::Signature * {
235         if (methodDef != nullptr) {
236             return methodDef->Function()->Signature();
237         }
238         if (etsFunctionType->CallSignatures().size() != 1) {
239             const auto loc = methodDef != nullptr ? methodDef->Start() : lexer::SourcePosition();
240             ThrowError("Method overloads are not supported", loc);
241         }
242         return etsFunctionType->CallSignatures()[0];
243     }();
244 
245     const auto *func = sig->Function();
246     GenTypeParameters(func->TypeParams());
247     Out("(");
248 
249     GenSeparated(sig->Params(), [this](varbinder::LocalVariable *param) {
250         Out(param->Name());
251         const auto *paramType = param->TsType();
252 
253         if (param->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
254             Out("?");
255         }
256         Out(": ");
257         GenType(paramType);
258     });
259 
260     const auto *sigInfo = sig->GetSignatureInfo();
261     if (sigInfo->restVar != nullptr) {
262         if (!sig->Params().empty()) {
263             Out(", ");
264         }
265         Out("...", sigInfo->restVar->Name().Mutf8(), ": ");
266         GenType(sigInfo->restVar->TsType());
267     }
268 
269     Out(")");
270 
271     GenFunctionBody(methodDef, sig, isConstructor, isSetter);
272 }
273 
GenEnumType(const checker::ETSIntEnumType * enumType)274 void TSDeclGen::GenEnumType(const checker::ETSIntEnumType *enumType)
275 {
276     for (auto *member : enumType->GetMembers()) {
277         Out(INDENT);
278         if (!member->IsTSEnumMember()) {
279             ThrowError("Member of enum not of type TSEnumMember", member->Start());
280         }
281 
282         const auto *enumMember = member->AsTSEnumMember();
283         Out(GetKeyIdent(enumMember->Key())->Name().Mutf8());
284         const auto *init = enumMember->Init();
285         if (init != nullptr) {
286             Out(" = ");
287 
288             if (!init->IsLiteral()) {
289                 ThrowError("Only literal enum initializers are supported", member->Start());
290             }
291 
292             GenLiteral(init->AsLiteral());
293         }
294 
295         Out(",");
296         OutEndl();
297     }
298 }
299 
GenUnionType(const checker::ETSUnionType * unionType)300 void TSDeclGen::GenUnionType(const checker::ETSUnionType *unionType)
301 {
302     GenSeparated(
303         unionType->ConstituentTypes(), [this](checker::Type *arg) { GenType(arg); }, " | ");
304 }
305 
GenObjectType(const checker::ETSObjectType * objectType)306 void TSDeclGen::GenObjectType(const checker::ETSObjectType *objectType)
307 {
308     if (objectType->IsETSStringType()) {
309         Out("string");
310         return;
311     }
312     if (objectType->HasObjectFlag(checker::ETSObjectFlags::UNBOXABLE_TYPE)) {
313         Out("number");  // NOTE(ivagin): create precise builtin type
314         return;
315     }
316     if (objectType->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL)) {
317         const auto *invoke = objectType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(
318             checker::FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
319         ASSERT(invoke && invoke->TsType() && invoke->TsType()->IsETSFunctionType());
320         GenType(invoke->TsType());
321         return;
322     }
323     if (objectType->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC)) {
324         Out("any");
325         return;
326     }
327 
328     auto typeName = objectType->Name();
329     if (typeName.Empty()) {
330         Warning("Object type name is empty");
331         Out("any");
332     } else {
333         Out(typeName);
334     }
335 
336     const auto &typeArgs = objectType->TypeArguments();
337     if (!typeArgs.empty()) {
338         Out("<");
339         GenSeparated(typeArgs, [this](checker::Type *arg) { GenType(arg); });
340         Out(">");
341     }
342 }
343 
GenTypeParameters(const ir::TSTypeParameterDeclaration * typeParams)344 void TSDeclGen::GenTypeParameters(const ir::TSTypeParameterDeclaration *typeParams)
345 {
346     if (typeParams != nullptr) {
347         Out("<");
348         GenSeparated(typeParams->Params(), [this](ir::TSTypeParameter *param) {
349             Out(param->Name()->Name());
350             auto *constraint = param->Constraint();
351             if (constraint != nullptr) {
352                 Out(" extends ");
353                 GenType(constraint->GetType(checker_));
354             }
355         });
356         Out(">");
357     }
358 }
359 
GenExport(const ir::Identifier * symbol)360 void TSDeclGen::GenExport(const ir::Identifier *symbol)
361 {
362     const auto symbolName = symbol->Name().Mutf8();
363     Out("export {", symbolName, "};");
364     OutEndl();
365     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
366         Out("exports.", symbolName, " = ", symbolName, ";");
367     }
368     OutEndl();
369 }
370 
GenExport(const ir::Identifier * symbol,const std::string & alias)371 void TSDeclGen::GenExport(const ir::Identifier *symbol, const std::string &alias)
372 {
373     const auto symbolName = symbol->Name().Mutf8();
374     Out("export {", symbolName, " as ", alias, "};");
375     OutEndl();
376     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
377         Out("exports.", alias, " = ", symbolName, ";");
378     }
379     OutEndl();
380 }
381 
GenDefaultExport(const ir::Identifier * symbol)382 void TSDeclGen::GenDefaultExport(const ir::Identifier *symbol)
383 {
384     const auto symbolName = symbol->Name().Mutf8();
385     Out("export default ", symbolName, ";");
386     OutEndl();
387     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
388         Out("exports.default = ", symbolName, ";");
389     }
390     OutEndl();
391 }
392 
ExportIfNeeded(const ir::Identifier * symbol)393 void TSDeclGen::ExportIfNeeded(const ir::Identifier *symbol)
394 {
395     if (symbol->Parent()->IsExported()) {
396         GenExport(symbol);
397     }
398     if (symbol->Parent()->IsExportedType()) {
399         GenExport(symbol);
400     }
401     if (symbol->Parent()->IsDefaultExported()) {
402         GenDefaultExport(symbol);
403     }
404 }
405 
406 template <class T>
GenModifier(const T * node)407 void TSDeclGen::GenModifier(const T *node)
408 {
409     if (state_.inInterface) {
410         return;
411     }
412 
413     if (node->IsPrivate()) {
414         Out("private ");
415     }
416     if (node->IsProtected()) {
417         Out("protected ");
418     }
419     if (node->IsPublic()) {
420         Out("public ");
421     }
422     if (node->IsReadonly()) {
423         Out("readonly ");
424     }
425     if (node->IsStatic()) {
426         Out("static ");
427     }
428 }
429 
GenImportDeclaration(const ir::ETSImportDeclaration * importDeclaration)430 void TSDeclGen::GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration)
431 {
432     DebugPrint("GenImportDeclaration");
433     if (importDeclaration->IsPureDynamic()) {
434         return;
435     }
436 
437     const auto &specifiers = importDeclaration->Specifiers();
438     Out("import { ");
439     GenSeparated(specifiers, [this, &importDeclaration](ir::AstNode *specifier) {
440         if (!specifier->IsImportSpecifier()) {
441             ThrowError("Only import specifiers are supported", importDeclaration->Start());
442         }
443 
444         const auto local = specifier->AsImportSpecifier()->Local()->Name();
445         const auto imported = specifier->AsImportSpecifier()->Imported()->Name();
446         if (local != imported) {
447             ThrowError("Imports with local bindings are not supported", importDeclaration->Start());
448         }
449 
450         Out(local);
451     });
452 
453     auto source = importDeclaration->Source()->Str().Mutf8();
454     Out(" } from \"", source, "\";");
455     OutEndl(2U);
456 }
457 
GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration * typeAlias)458 void TSDeclGen::GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)
459 {
460     const auto name = typeAlias->Id()->Name().Mutf8();
461     DebugPrint("GenTypeAliasDeclaration: " + name);
462     const auto *aliasedType = typeAlias->TypeAnnotation()->GetType(checker_);
463     Out("type ", name, " = ");
464     GenType(aliasedType);
465     Out(";");
466     OutEndl();
467 
468     ExportIfNeeded(typeAlias->Id());
469     OutEndl();
470 }
471 
GenEnumDeclaration(const ir::TSEnumDeclaration * enumDecl)472 void TSDeclGen::GenEnumDeclaration(const ir::TSEnumDeclaration *enumDecl)
473 {
474     const auto enumIdent = GetKeyIdent(enumDecl->Key());
475     const auto enumName = enumIdent->Name().Mutf8();
476     DebugPrint("GenEnumDeclaration: " + enumName);
477     Out("enum ", enumName, " {");
478     OutEndl();
479 
480     ASSERT(enumDecl->TsType()->IsETSIntEnumType());
481     GenEnumType(enumDecl->TsType()->AsETSIntEnumType());
482 
483     Out("}");
484     OutEndl();
485 
486     ExportIfNeeded(enumIdent);
487     OutEndl();
488 }
489 
GenInterfaceDeclaration(const ir::TSInterfaceDeclaration * interfaceDecl)490 void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)
491 {
492     state_.inInterface = true;
493     const auto interfaceName = interfaceDecl->Id()->Name().Mutf8();
494     DebugPrint("GenInterfaceDeclaration: " + interfaceName);
495     Out("interface ", interfaceName);
496 
497     GenTypeParameters(interfaceDecl->TypeParams());
498 
499     Out(" {");
500     OutEndl();
501 
502     for (auto *prop : interfaceDecl->Body()->Body()) {
503         if (prop->IsMethodDefinition()) {
504             GenMethodDeclaration(prop->AsMethodDefinition());
505             for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
506                 GenMethodDeclaration(methodDef);
507             }
508         }
509         if (prop->IsClassProperty()) {
510             GenPropDeclaration(prop->AsClassProperty());
511         }
512     }
513 
514     Out("}");
515     OutEndl();
516 
517     ExportIfNeeded(interfaceDecl->Id());
518     OutEndl();
519 }
520 
GenClassDeclaration(const ir::ClassDeclaration * classDecl)521 void TSDeclGen::GenClassDeclaration(const ir::ClassDeclaration *classDecl)
522 {
523     const auto *classDef = classDecl->Definition();
524     std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";";
525     std::replace(classDescriptor.begin(), classDescriptor.end(), '.', '/');
526     state_.currentClassDescriptor = classDescriptor;
527     const auto className = classDef->Ident()->Name().Mutf8();
528     state_.inGlobalClass = classDef->IsGlobal();
529 
530     DebugPrint("GenClassDeclaration: " + className);
531 
532     if (className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS ||
533         className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos)) {
534         return;
535     }
536 
537     if (!state_.inGlobalClass) {
538         Out("class ", className);
539         GenTypeParameters(classDef->TypeParams());
540 
541         const auto *super = classDef->Super();
542         state_.super = super;
543         if (super != nullptr) {
544             Out(" extends ");
545             GenType(super->TsType());
546         }
547 
548         const auto &interfaces = classDef->TsType()->AsETSObjectType()->Interfaces();
549         if (!interfaces.empty()) {
550             Out(" implements ");
551             ASSERT(classDef->TsType()->IsETSObjectType());
552             GenSeparated(interfaces, [this](checker::ETSObjectType *interface) { GenType(interface); });
553         }
554 
555         Out(" {");
556         OutEndl();
557     }
558 
559     for (const auto *prop : classDef->Body()) {
560         if (prop->IsMethodDefinition()) {
561             GenMethodDeclaration(prop->AsMethodDefinition());
562             for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
563                 GenMethodDeclaration(methodDef);
564             }
565         } else if (prop->IsClassProperty()) {
566             GenPropDeclaration(prop->AsClassProperty());
567         }
568     }
569 
570     if (!state_.inGlobalClass) {
571         Out("};");
572         OutEndl();
573         Out("(", className, " as any) = (globalThis as any).Panda.getClass('", state_.currentClassDescriptor, "');");
574         OutEndl();
575         ExportIfNeeded(classDef->Ident());
576         OutEndl();
577     }
578 }
579 
GenMethodDeclaration(const ir::MethodDefinition * methodDef)580 void TSDeclGen::GenMethodDeclaration(const ir::MethodDefinition *methodDef)
581 {
582     const auto methodIdent = GetKeyIdent(methodDef->Key());
583     const auto methodName = methodIdent->Name().Mutf8();
584     if (methodName.find('#') != std::string::npos) {
585         return;
586     }
587 
588     if (state_.inGlobalClass) {
589         Out("function ");
590     } else {
591         Out(INDENT);
592         GenModifier(methodDef);
593     }
594 
595     if (methodDef->Kind() == ir::MethodDefinitionKind::GET) {
596         Out("get ");
597     }
598     if (methodDef->Kind() == ir::MethodDefinitionKind::SET) {
599         Out("set ");
600     }
601 
602     DebugPrint("  GenMethodDeclaration: " + methodName);
603     Out(methodName);
604 
605     if (methodDef->TsType() == nullptr) {
606         Warning("Untyped method encountered: " + methodName);
607         Out(": any");
608     } else {
609         GenFunctionType(methodDef->TsType()->AsETSFunctionType(), methodDef);
610     }
611 
612     Out(";");
613     OutEndl();
614 
615     if (state_.inGlobalClass) {
616         Out("(", methodName, " as any) = ETSGLOBAL.", methodName, ";");
617         OutEndl();
618         ExportIfNeeded(methodIdent);
619         if (methodName == compiler::Signatures::INIT_METHOD) {
620             Out(methodName, "();");
621         }
622         OutEndl(2U);
623     }
624 }
625 
GenPropDeclaration(const ir::ClassProperty * classProp)626 void TSDeclGen::GenPropDeclaration(const ir::ClassProperty *classProp)
627 {
628     if (state_.inGlobalClass) {
629         GenGlobalVarDeclaration(classProp);
630         return;
631     }
632 
633     const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
634     DebugPrint("  GenPropDeclaration: " + propName);
635 
636     Out(INDENT);
637     GenModifier(classProp);
638     Out(propName);
639 
640     Out(": ");
641     GenType(classProp->TsType());
642     if (!state_.inInterface) {
643         Out(" = {} as any");
644     }
645     Out(";");
646     OutEndl();
647 }
648 
GenGlobalVarDeclaration(const ir::ClassProperty * globalVar)649 void TSDeclGen::GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)
650 {
651     if (!globalVar->IsExported() && !globalVar->IsDefaultExported()) {
652         return;
653     }
654 
655     const auto symbol = GetKeyIdent(globalVar->Key());
656     const auto varName = symbol->Name().Mutf8();
657     DebugPrint("GenGlobalVarDeclaration: " + varName);
658     if (!globalVar->IsConst()) {
659         Warning("Not constant global variables are not supported, variable \"" + varName + "\" was skipped");
660         return;
661     }
662 
663     Out("const ", varName, ": ");
664     GenType(globalVar->TsType());
665     Out(" = ETSGLOBAL.", varName, ';');
666     OutEndl();
667 
668     GenExport(symbol);
669     OutEndl();
670 }
671 
GenerateTsDeclarations(checker::ETSChecker * checker,const ark::es2panda::parser::Program * program,const std::string & outPath)672 bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program,
673                             const std::string &outPath)
674 {
675     TSDeclGen declBuilder(checker, program);
676     declBuilder.Generate();
677 
678     std::ofstream outStream(outPath);
679     if (outStream.fail()) {
680         std::cerr << "Failed to open file: " << outPath << std::endl;
681         return false;
682     }
683 
684     outStream << declBuilder.Output().str();
685     outStream.close();
686 
687     return true;
688 }
689 }  // namespace ark::es2panda::declgen_ets2ts
690