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