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