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([[maybe_unused]] 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 Out(local);
447 if (local != imported) {
448 ThrowError("Imports with local bindings are not supported", importDeclaration->Start());
449 }
450 });
451
452 auto source = importDeclaration->Source()->Str().Mutf8();
453 Out(" } from \"", source, "\";");
454 OutEndl(2U);
455 }
456
GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)457 void TSDeclGen::GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)
458 {
459 const auto name = typeAlias->Id()->Name().Mutf8();
460 DebugPrint("GenTypeAliasDeclaration: " + name);
461 const auto *aliasedType = typeAlias->TypeAnnotation()->GetType(checker_);
462 Out("type ", name, " = ");
463 GenType(aliasedType);
464 Out(";");
465 OutEndl();
466
467 ExportIfNeeded(typeAlias->Id());
468 OutEndl();
469 }
470
GenEnumDeclaration(const ir::TSEnumDeclaration *enumDecl)471 void TSDeclGen::GenEnumDeclaration(const ir::TSEnumDeclaration *enumDecl)
472 {
473 const auto enumIdent = GetKeyIdent(enumDecl->Key());
474 const auto enumName = enumIdent->Name().Mutf8();
475 DebugPrint("GenEnumDeclaration: " + enumName);
476 Out("enum ", enumName, " {");
477 OutEndl();
478
479 ASSERT(enumDecl->TsType()->IsETSIntEnumType());
480 GenEnumType(enumDecl->TsType()->AsETSIntEnumType());
481
482 Out("}");
483 OutEndl();
484
485 ExportIfNeeded(enumIdent);
486 OutEndl();
487 }
488
GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)489 void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)
490 {
491 state_.inInterface = true;
492 const auto interfaceName = interfaceDecl->Id()->Name().Mutf8();
493 DebugPrint("GenInterfaceDeclaration: " + interfaceName);
494 Out("interface ", interfaceName);
495
496 GenTypeParameters(interfaceDecl->TypeParams());
497
498 Out(" {");
499 OutEndl();
500
501 for (auto *prop : interfaceDecl->Body()->Body()) {
502 if (prop->IsMethodDefinition()) {
503 GenMethodDeclaration(prop->AsMethodDefinition());
504 for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
505 GenMethodDeclaration(methodDef);
506 }
507 }
508 if (prop->IsClassProperty()) {
509 GenPropDeclaration(prop->AsClassProperty());
510 }
511 }
512
513 Out("}");
514 OutEndl();
515
516 ExportIfNeeded(interfaceDecl->Id());
517 OutEndl();
518 }
519
GenClassDeclaration(const ir::ClassDeclaration *classDecl)520 void TSDeclGen::GenClassDeclaration(const ir::ClassDeclaration *classDecl)
521 {
522 const auto *classDef = classDecl->Definition();
523 std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";";
524 std::replace(classDescriptor.begin(), classDescriptor.end(), '.', '/');
525 state_.currentClassDescriptor = classDescriptor;
526 const auto className = classDef->Ident()->Name().Mutf8();
527 state_.inGlobalClass = classDef->IsGlobal();
528
529 DebugPrint("GenClassDeclaration: " + className);
530
531 if (className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS ||
532 className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos)) {
533 return;
534 }
535
536 if (!state_.inGlobalClass) {
537 Out("class ", className);
538 GenTypeParameters(classDef->TypeParams());
539
540 const auto *super = classDef->Super();
541 state_.super = super;
542 if (super != nullptr) {
543 Out(" extends ");
544 GenType(super->TsType());
545 }
546
547 const auto &interfaces = classDef->TsType()->AsETSObjectType()->Interfaces();
548 if (!interfaces.empty()) {
549 Out(" implements ");
550 ASSERT(classDef->TsType()->IsETSObjectType());
551 GenSeparated(interfaces, [this](checker::ETSObjectType *interface) { GenType(interface); });
552 }
553
554 Out(" {");
555 OutEndl();
556 }
557
558 for (const auto *prop : classDef->Body()) {
559 if (prop->IsMethodDefinition()) {
560 GenMethodDeclaration(prop->AsMethodDefinition());
561 for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
562 GenMethodDeclaration(methodDef);
563 }
564 } else if (prop->IsClassProperty()) {
565 GenPropDeclaration(prop->AsClassProperty());
566 }
567 }
568
569 if (!state_.inGlobalClass) {
570 Out("};");
571 OutEndl();
572 Out("(", className, " as any) = (globalThis as any).Panda.getClass('", state_.currentClassDescriptor, "');");
573 OutEndl();
574 ExportIfNeeded(classDef->Ident());
575 OutEndl();
576 }
577 }
578
GenMethodDeclaration(const ir::MethodDefinition *methodDef)579 void TSDeclGen::GenMethodDeclaration(const ir::MethodDefinition *methodDef)
580 {
581 const auto methodIdent = GetKeyIdent(methodDef->Key());
582 const auto methodName = methodIdent->Name().Mutf8();
583 if (methodName.find('#') != std::string::npos) {
584 return;
585 }
586
587 if (state_.inGlobalClass) {
588 Out("function ");
589 } else {
590 Out(INDENT);
591 GenModifier(methodDef);
592 }
593
594 if (methodDef->Kind() == ir::MethodDefinitionKind::GET) {
595 Out("get ");
596 }
597 if (methodDef->Kind() == ir::MethodDefinitionKind::SET) {
598 Out("set ");
599 }
600
601 DebugPrint(" GenMethodDeclaration: " + methodName);
602 Out(methodName);
603
604 if (methodDef->TsType() == nullptr) {
605 Warning("Untyped method encountered: " + methodName);
606 Out(": any");
607 } else {
608 GenFunctionType(methodDef->TsType()->AsETSFunctionType(), methodDef);
609 }
610
611 Out(";");
612 OutEndl();
613
614 if (state_.inGlobalClass) {
615 Out("(", methodName, " as any) = ETSGLOBAL.", methodName, ";");
616 OutEndl();
617 ExportIfNeeded(methodIdent);
618 if (methodName == compiler::Signatures::INIT_METHOD) {
619 Out(methodName, "();");
620 }
621 OutEndl(2U);
622 }
623 }
624
GenPropDeclaration(const ir::ClassProperty *classProp)625 void TSDeclGen::GenPropDeclaration(const ir::ClassProperty *classProp)
626 {
627 if (state_.inGlobalClass) {
628 GenGlobalVarDeclaration(classProp);
629 return;
630 }
631
632 const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
633 DebugPrint(" GenPropDeclaration: " + propName);
634
635 Out(INDENT);
636 GenModifier(classProp);
637 Out(propName);
638
639 Out(": ");
640 GenType(classProp->TsType());
641 if (!state_.inInterface) {
642 Out(" = {} as any");
643 }
644 Out(";");
645 OutEndl();
646 }
647
GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)648 void TSDeclGen::GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)
649 {
650 if (!globalVar->IsExported() && !globalVar->IsDefaultExported()) {
651 return;
652 }
653
654 const auto symbol = GetKeyIdent(globalVar->Key());
655 const auto varName = symbol->Name().Mutf8();
656 DebugPrint("GenGlobalVarDeclaration: " + varName);
657 if (!globalVar->IsConst()) {
658 Warning("Not constant global variables are not supported, variable \"" + varName + "\" was skipped");
659 return;
660 }
661
662 Out("const ", varName, ": ");
663 GenType(globalVar->TsType());
664 Out(" = ETSGLOBAL.", varName, ';');
665 OutEndl();
666
667 GenExport(symbol);
668 OutEndl();
669 }
670
GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program, const std::string &outPath)671 bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program,
672 const std::string &outPath)
673 {
674 TSDeclGen declBuilder(checker, program);
675 declBuilder.Generate();
676
677 std::ofstream outStream(outPath);
678 if (outStream.fail()) {
679 std::cerr << "Failed to open file: " << outPath << std::endl;
680 return false;
681 }
682
683 outStream << declBuilder.Output().str();
684 outStream.close();
685
686 return true;
687 }
688 } // namespace ark::es2panda::declgen_ets2ts
689