• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #include <cctype>
18 
19 #include "checker/types/ets/etsTupleType.h"
20 #include "generated/diagnostic.h"
21 #include "ir/base/classProperty.h"
22 #include "ir/base/methodDefinition.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/ets/etsImportDeclaration.h"
25 #include "ir/ets/etsReExportDeclaration.h"
26 #include "ir/ets/etsTuple.h"
27 #include "ir/ets/etsUnionType.h"
28 #include "ir/expressions/identifier.h"
29 #include "ir/expressions/literals/numberLiteral.h"
30 #include "ir/module/importSpecifier.h"
31 #include "ir/statements/blockStatement.h"
32 #include "ir/statements/classDeclaration.h"
33 #include "ir/ts/tsEnumMember.h"
34 #include "ir/ts/tsInterfaceBody.h"
35 #include "ir/ts/tsTypeAliasDeclaration.h"
36 #include "ir/ts/tsTypeParameter.h"
37 #include "compiler/lowering/util.h"
38 
39 #define DEBUG_PRINT 0
40 
41 namespace ark::es2panda::declgen_ets2ts {
42 
DebugPrint(const std::string & msg)43 static void DebugPrint([[maybe_unused]] const std::string &msg)
44 {
45 #if DEBUG_PRINT
46     std::cerr << msg << std::endl;
47 #endif
48 }
49 
Generate()50 bool TSDeclGen::Generate()
51 {
52     if (!GenGlobalDescriptor()) {
53         return false;
54     }
55     CollectIndirectExportDependencies();
56     GenDeclarations();
57     return true;
58 }
59 
GenGlobalDescriptor()60 bool TSDeclGen::GenGlobalDescriptor()
61 {
62     if (program_->GlobalClass() == nullptr) {
63         const auto loc = lexer::SourcePosition();
64         LogError(diagnostic::UNSUPPORTED_ENCODING_SPECIFICATIONS, {}, loc);
65         return false;
66     }
67     globalDesc_ =
68         checker::ETSObjectType::NameToDescriptor(program_->GlobalClass()->TsType()->AsETSObjectType()->AssemblerName());
69     OutTs("let ETSGLOBAL = (globalThis as any).Panda.getClass('", globalDesc_, "');");
70     OutEndlTs();
71     OutTs("ETSGLOBAL.", compiler::Signatures::INIT_METHOD, "();");
72     OutEndlTs();
73     OutTs("export {};");
74     OutEndlTs();
75     return true;
76 }
77 
CollectIndirectExportDependencies()78 void TSDeclGen::CollectIndirectExportDependencies()
79 {
80     for (auto *stmt : program_->Ast()->Statements()) {
81         if (stmt->IsTSTypeAliasDeclaration()) {
82             ProcessTypeAliasDependencies(stmt->AsTSTypeAliasDeclaration());
83         } else if (stmt->IsClassDeclaration()) {
84             ProcessClassDependencies(stmt->AsClassDeclaration());
85         } else if (stmt->IsTSInterfaceDeclaration()) {
86             ProcessInterfaceDependencies(stmt->AsTSInterfaceDeclaration());
87         }
88     }
89 }
90 
ProcessTypeAliasDependencies(const ir::TSTypeAliasDeclaration * typeAliasDecl)91 void TSDeclGen::ProcessTypeAliasDependencies(const ir::TSTypeAliasDeclaration *typeAliasDecl)
92 {
93     const auto name = typeAliasDecl->Id()->Name().Mutf8();
94     const auto *aliasedType = typeAliasDecl->TypeAnnotation()->GetType(checker_);
95     const auto typeFlag = checker::ETSChecker::ETSType(aliasedType);
96     const auto *parent = typeAliasDecl->Id()->Parent();
97     if (!parent->IsExported() && !parent->IsDefaultExported()) {
98         return;
99     }
100     if (typeFlag == checker::TypeFlag::ETS_OBJECT || typeFlag == checker::TypeFlag::ETS_DYNAMIC_TYPE) {
101         auto objectType = aliasedType->AsETSObjectType();
102         if (objectType->IsETSStringType() || objectType->IsETSBigIntType() || objectType->IsETSUnboxableObject() ||
103             objectType->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL) ||
104             objectType->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC)) {
105             return;
106         }
107         auto typeName = objectType->Name();
108         AddObjectDependencies(typeName, name);
109     }
110     ProcessTypeAnnotationDependencies(typeAliasDecl->TypeAnnotation());
111 }
112 
ProcessTypeAnnotationDependencies(const ir::TypeNode * typeAnnotation)113 void TSDeclGen::ProcessTypeAnnotationDependencies(const ir::TypeNode *typeAnnotation)
114 {
115     if (typeAnnotation->IsETSTypeReference()) {
116         ProcessETSTypeReferenceDependencies(typeAnnotation->AsETSTypeReference());
117         return;
118     } else if (typeAnnotation->IsETSUnionType()) {
119         GenSeparated(
120             typeAnnotation->AsETSUnionType()->Types(),
121             [this](ir::TypeNode *arg) { ProcessTypeAnnotationDependencies(arg); }, "");
122     }
123 }
124 
ProcessETSTypeReferenceDependencies(const ir::ETSTypeReference * typeReference)125 void TSDeclGen::ProcessETSTypeReferenceDependencies(const ir::ETSTypeReference *typeReference)
126 {
127     const auto part = typeReference->Part();
128     auto partName = part->GetIdent()->Name().Mutf8();
129     if (part->TypeParams() != nullptr && part->TypeParams()->IsTSTypeParameterInstantiation()) {
130         indirectDependencyObjects_.insert(partName);
131         GenSeparated(
132             part->TypeParams()->Params(), [this](ir::TypeNode *param) { ProcessTypeAnnotationDependencies(param); },
133             "");
134         return;
135     } else if (part->Name()->IsTSQualifiedName() && part->Name()->AsTSQualifiedName()->Name() != nullptr) {
136         const auto qualifiedName = part->Name()->AsTSQualifiedName()->Name().Mutf8();
137         std::istringstream stream(qualifiedName.data());
138         std::string firstSegment;
139         if (std::getline(stream, firstSegment, '.')) {
140             importSet_.insert(firstSegment);
141             indirectDependencyObjects_.insert(firstSegment);
142         }
143     } else {
144         indirectDependencyObjects_.insert(partName);
145     }
146 }
147 
ProcessClassDependencies(const ir::ClassDeclaration * classDecl)148 void TSDeclGen::ProcessClassDependencies(const ir::ClassDeclaration *classDecl)
149 {
150     auto *classDef = classDecl->Definition();
151     if (classDef->Ident()->Name().Mutf8().find('#') != std::string::npos) {
152         return;
153     }
154 
155     if (!classDef->IsExported() && !classDef->IsDefaultExported()) {
156         return;
157     }
158 
159     state_.super = classDef->Super();
160     if (state_.super != nullptr) {
161         AddSuperType(state_.super);
162     }
163 
164     if (classDef->TsType() != nullptr && classDef->TsType()->IsETSObjectType()) {
165         ProcessInterfacesDependencies(classDef->TsType()->AsETSObjectType()->Interfaces());
166     }
167 
168     if (classDef->TypeParams() != nullptr) {
169         GenSeparated(
170             classDef->TypeParams()->Params(),
171             [this](ir::TSTypeParameter *param) {
172                 if (param->Constraint() == nullptr) {
173                     return;
174                 }
175                 AddSuperType(param->Constraint());
176             },
177             "");
178     }
179 
180     ProcessClassPropDependencies(classDef);
181 }
182 
ProcessClassPropDependencies(const ir::ClassDefinition * classDef)183 void TSDeclGen::ProcessClassPropDependencies(const ir::ClassDefinition *classDef)
184 {
185     for (const auto *prop : classDef->Body()) {
186         if (prop->IsClassProperty()) {
187             auto value = prop->AsClassProperty()->Value();
188             if (value != nullptr && value->IsETSNewClassInstanceExpression() &&
189                 value->AsETSNewClassInstanceExpression()->GetTypeRef() != nullptr &&
190                 value->AsETSNewClassInstanceExpression()->GetTypeRef()->IsETSTypeReference()) {
191                 auto typeReference = value->AsETSNewClassInstanceExpression()->GetTypeRef()->AsETSTypeReference();
192                 ProcessETSTypeReferenceDependencies(typeReference);
193                 continue;
194             }
195             if (prop->AsClassProperty()->TypeAnnotation() != nullptr) {
196                 ProcessTypeAnnotationDependencies(prop->AsClassProperty()->TypeAnnotation());
197                 continue;
198             }
199         } else if (prop->IsMethodDefinition()) {
200             ProcessClassMethodDependencies(prop->AsMethodDefinition());
201         } else if (prop->IsClassDeclaration() && classDef->IsNamespaceTransformed()) {
202             ProcessClassDependencies(prop->AsClassDeclaration());
203         }
204     }
205 }
206 
ProcessClassMethodDependencies(const ir::MethodDefinition * methodDef)207 void TSDeclGen::ProcessClassMethodDependencies(const ir::MethodDefinition *methodDef)
208 {
209     if (!methodDef->IsExported() && !methodDef->IsExportedType() && !methodDef->IsDefaultExported()) {
210         return;
211     }
212     auto methDefFunc = methodDef->Function();
213     if (methDefFunc == nullptr) {
214         return;
215     }
216     auto sig = methDefFunc->Signature();
217     GenSeparated(
218         sig->Params(), [this](varbinder::LocalVariable *param) { AddSuperType(param->TsType()); }, "");
219 
220     AddSuperType(sig->ReturnType());
221 }
222 
ProcessInterfaceDependencies(const ir::TSInterfaceDeclaration * interfaceDecl)223 void TSDeclGen::ProcessInterfaceDependencies(const ir::TSInterfaceDeclaration *interfaceDecl)
224 {
225     if (interfaceDecl->Id()->Name().Mutf8().find('#') != std::string::npos) {
226         return;
227     }
228 
229     if (!interfaceDecl->IsExported() && !interfaceDecl->IsExportedType()) {
230         return;
231     }
232 
233     if (interfaceDecl->TsType() != nullptr && interfaceDecl->TsType()->IsETSObjectType()) {
234         ProcessInterfacesDependencies(interfaceDecl->TsType()->AsETSObjectType()->Interfaces());
235     }
236 
237     if (interfaceDecl->TypeParams() != nullptr) {
238         GenSeparated(
239             interfaceDecl->TypeParams()->Params(),
240             [this](ir::TSTypeParameter *param) {
241                 if (param->Constraint() == nullptr) {
242                     return;
243                 }
244                 AddSuperType(param->Constraint());
245             },
246             "");
247     }
248 
249     ProcessInterfacePropDependencies(interfaceDecl);
250 }
251 
ProcessInterfacePropDependencies(const ir::TSInterfaceDeclaration * interfaceDecl)252 void TSDeclGen::ProcessInterfacePropDependencies(const ir::TSInterfaceDeclaration *interfaceDecl)
253 {
254     for (const auto *prop : interfaceDecl->Body()->Body()) {
255         if (prop->IsMethodDefinition()) {
256             ProcessInterfaceMethodDependencies(prop->AsMethodDefinition());
257         }
258     }
259 }
260 
ProcessInterfaceMethodDependencies(const ir::MethodDefinition * methodDef)261 void TSDeclGen::ProcessInterfaceMethodDependencies(const ir::MethodDefinition *methodDef)
262 {
263     auto methDefFunc = methodDef->Function();
264     if (methDefFunc == nullptr) {
265         return;
266     }
267     auto sig = methDefFunc->Signature();
268     GenSeparated(
269         sig->Params(), [this](varbinder::LocalVariable *param) { AddSuperType(param->TsType()); }, "");
270 
271     AddSuperType(sig->ReturnType());
272 }
273 
AddSuperType(const ir::Expression * super)274 void TSDeclGen::AddSuperType(const ir::Expression *super)
275 {
276     if (super->TsType() == nullptr) {
277         return;
278     }
279     AddSuperType(super->TsType());
280 }
281 
AddSuperType(const checker::Type * tsType)282 void TSDeclGen::AddSuperType(const checker::Type *tsType)
283 {
284     const auto superType = checker::ETSChecker::ETSType(tsType);
285     if (superType == checker::TypeFlag::ETS_OBJECT) {
286         auto objectType = tsType->AsETSObjectType();
287         AddObjectDependencies(objectType->Name());
288     } else if (superType == checker::TypeFlag::ETS_UNION) {
289         auto unionType = tsType->AsETSUnionType();
290         std::vector<checker::Type *> filteredTypes = FilterUnionTypes(unionType->ConstituentTypes());
291         GenSeparated(
292             filteredTypes, [this](checker::Type *type) { AddSuperType(type); }, "");
293     }
294 }
295 
ProcessInterfacesDependencies(const ArenaVector<checker::ETSObjectType * > & interfaces)296 void TSDeclGen::ProcessInterfacesDependencies(const ArenaVector<checker::ETSObjectType *> &interfaces)
297 {
298     GenSeparated(
299         interfaces,
300         [this](checker::ETSObjectType *interface) {
301             if (checker::ETSChecker::ETSType(interface) == checker::TypeFlag::ETS_OBJECT ||
302                 checker::ETSChecker::ETSType(interface) == checker::TypeFlag::ETS_DYNAMIC_TYPE) {
303                 AddObjectDependencies(interface->Name());
304             }
305         },
306         "");
307 }
308 
AddObjectDependencies(const util::StringView & typeName,const std::string & alias)309 void TSDeclGen::AddObjectDependencies(const util::StringView &typeName, const std::string &alias)
310 {
311     if (typeName.Empty()) {
312         return;
313     }
314     importSet_.insert(typeName.Mutf8());
315     indirectDependencyObjects_.insert(typeName.Mutf8());
316     if (!alias.empty()) {
317         typeAliasMap_[alias] = typeName.Mutf8();
318     }
319 }
320 
GenDeclarations()321 void TSDeclGen::GenDeclarations()
322 {
323     for (auto *globalStatement : program_->Ast()->Statements()) {
324         ResetState();
325         ResetClassNode();
326         if (globalStatement->IsClassDeclaration()) {
327             GenClassDeclaration(globalStatement->AsClassDeclaration());
328         } else if (globalStatement->IsTSInterfaceDeclaration()) {
329             GenInterfaceDeclaration(globalStatement->AsTSInterfaceDeclaration());
330         } else if (globalStatement->IsTSTypeAliasDeclaration()) {
331             GenTypeAliasDeclaration(globalStatement->AsTSTypeAliasDeclaration());
332         } else if (globalStatement->IsETSReExportDeclaration()) {
333             GenReExportDeclaration(globalStatement->AsETSReExportDeclaration());
334         }
335     }
336 }
337 
GenImportDeclarations()338 void TSDeclGen::GenImportDeclarations()
339 {
340     for (auto *globalStatement : program_->Ast()->Statements()) {
341         if (globalStatement->IsETSImportDeclaration()) {
342             GenImportDeclaration(globalStatement->AsETSImportDeclaration());
343         }
344     }
345 }
346 
GenImportRecordDeclarations(const std::string & source)347 void TSDeclGen::GenImportRecordDeclarations(const std::string &source)
348 {
349     const std::string recordKey = "Record";
350     if (indirectDependencyObjects_.find(recordKey) != indirectDependencyObjects_.end()) {
351         OutDts("import type { Record } from \"", source, "\";\n");
352     }
353 }
354 
355 template <class T, class CB>
GenSeparated(const T & container,const CB & cb,const char * separator,bool isReExport,bool isDtsExport)356 void TSDeclGen::GenSeparated(const T &container, const CB &cb, const char *separator, bool isReExport, bool isDtsExport)
357 {
358     if (container.empty()) {
359         return;
360     }
361 
362     cb(container[0]);
363     for (std::size_t i = 1; i < container.size(); ++i) {
364         if (isReExport) {
365             OutTs(separator);
366         }
367         if (isDtsExport) {
368             OutDts(separator);
369         }
370         cb(container[i]);
371     }
372 }
373 
LogError(const diagnostic::DiagnosticKind & kind,const util::DiagnosticMessageParams & params={},const lexer::SourcePosition & pos=lexer::SourcePosition ())374 void TSDeclGen::LogError(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &params = {},
375                          const lexer::SourcePosition &pos = lexer::SourcePosition())
376 {
377     diagnosticEngine_.LogDiagnostic(kind, params, pos);
378 }
379 
LogWarning(const diagnostic::DiagnosticKind & kind,const util::DiagnosticMessageParams & params={},const lexer::SourcePosition & pos=lexer::SourcePosition ())380 void TSDeclGen::LogWarning(const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams &params = {},
381                            const lexer::SourcePosition &pos = lexer::SourcePosition())
382 {
383     ES2PANDA_ASSERT(kind.Type() == util::DiagnosticType::DECLGEN_ETS2TS_WARNING);
384     LogError(kind, params, pos);
385 }
386 
GetKeyIdent(const ir::Expression * key)387 const ir::Identifier *TSDeclGen::GetKeyIdent(const ir::Expression *key)
388 {
389     if (!key->IsIdentifier()) {
390         LogError(diagnostic::IDENT_KEY_SUPPORT, {}, key->Start());
391     }
392 
393     return key->AsIdentifier();
394 }
395 
GetDebugTypeName(const checker::Type * checkerType)396 static char const *GetDebugTypeName(const checker::Type *checkerType)
397 {
398 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
399 #define TYPE_CHECKS(type_flag, typeName)                                                    \
400     if (checkerType->Is##typeName()) {                                                      \
401         /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \
402         return #typeName;                                                                   \
403     }
404     TYPE_MAPPING(TYPE_CHECKS)
405 #undef TYPE_CHECKS
406     return "unknown type";
407 }
408 
GenType(const checker::Type * checkerType)409 void TSDeclGen::GenType(const checker::Type *checkerType)
410 {
411     DebugPrint("  GenType: ");
412 #if DEBUG_PRINT
413     const auto var_name = checkerType->Variable() == nullptr ? "" : checkerType->Variable()->Name().Mutf8();
414     DebugPrint(std::string("  Converting type: ") + GetDebugTypeName(checkerType) + " (" + var_name + ")");
415 #endif
416 
417     importSet_.insert(checkerType->ToString());
418 
419     if (HandleBasicTypes(checkerType)) {
420         return;
421     }
422 
423     if (checkerType->IsETSFunctionType()) {
424         HandleFunctionType(checkerType);
425         return;
426     }
427 
428     if (HandleETSSpecificTypes(checkerType)) {
429         return;
430     }
431 
432     LogError(diagnostic::UNSUPPORTED_TYPE, {GetDebugTypeName(checkerType)});
433 }
434 
HandleBasicTypes(const checker::Type * checkerType)435 bool TSDeclGen::HandleBasicTypes(const checker::Type *checkerType)
436 {
437     if (checkerType->IsETSEnumType()) {
438         OutDts(checkerType->ToString());
439         return true;
440     }
441     if (checkerType->HasTypeFlag(checker::TypeFlag::CHAR)) {
442         OutDts("string");
443         return true;
444     }
445     if (checkerType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
446         OutDts("number");
447         return true;
448     }
449     return false;
450 }
451 
HandleFunctionType(const checker::Type * checkerType)452 void TSDeclGen::HandleFunctionType(const checker::Type *checkerType)
453 {
454     if (!state_.inUnionBodyStack.empty() && state_.inUnionBodyStack.top()) {
455         OutDts("(");
456         GenFunctionType(checkerType->AsETSFunctionType());
457         OutDts(")");
458     } else {
459         GenFunctionType(checkerType->AsETSFunctionType());
460     }
461 }
462 
HandleETSSpecificTypes(const checker::Type * checkerType)463 bool TSDeclGen::HandleETSSpecificTypes(const checker::Type *checkerType)
464 {
465     switch (checker::ETSChecker::ETSType(checkerType)) {
466         case checker::TypeFlag::ETS_VOID:
467         case checker::TypeFlag::ETS_NULL:
468         case checker::TypeFlag::ETS_UNDEFINED:
469         case checker::TypeFlag::ETS_BOOLEAN:
470         case checker::TypeFlag::ETS_TYPE_PARAMETER:
471         case checker::TypeFlag::ETS_NONNULLISH:
472         case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER:
473         case checker::TypeFlag::ETS_NEVER:
474         case checker::TypeFlag::ETS_READONLY:
475             OutDts(checkerType->ToString());
476             return true;
477 
478         case checker::TypeFlag::ETS_OBJECT:
479         case checker::TypeFlag::ETS_DYNAMIC_TYPE:
480             return HandleObjectType(checkerType);
481 
482         case checker::TypeFlag::ETS_ARRAY:
483             HandleArrayType(checkerType);
484             return true;
485 
486         case checker::TypeFlag::ETS_UNION:
487             GenUnionType(checkerType->AsETSUnionType());
488             return true;
489         case checker::TypeFlag::ETS_TUPLE:
490             GenTupleType(checkerType->AsETSTupleType());
491             return true;
492         case checker::TypeFlag::ETS_ANY:
493             OutDts("ESObject");
494             return true;
495         default:
496             LogError(diagnostic::UNSUPPORTED_TYPE, {GetDebugTypeName(checkerType)});
497     }
498     return false;
499 }
500 
HandleObjectType(const checker::Type * checkerType)501 bool TSDeclGen::HandleObjectType(const checker::Type *checkerType)
502 {
503     std::string typeStr = checkerType->ToString();
504     if (typeStr == "Boolean") {
505         OutDts("boolean");
506     } else if (stringTypes_.count(typeStr) != 0U) {
507         OutDts("string");
508     } else if (numberTypes_.count(typeStr) != 0U) {
509         OutDts("number");
510     } else if (typeStr == "BigInt") {
511         OutDts("bigint");
512     } else if (typeStr == "ESValue") {
513         OutDts("ESObject");
514     } else {
515         GenObjectType(checkerType->AsETSObjectType());
516     }
517     return true;
518 }
519 
HandleArrayType(const checker::Type * checkerType)520 void TSDeclGen::HandleArrayType(const checker::Type *checkerType)
521 {
522     const auto *elementType = checkerType->AsETSArrayType()->ElementType();
523     bool needParentheses = elementType->IsETSUnionType() || elementType->IsETSFunctionType();
524     if (needParentheses) {
525         OutDts("(");
526         GenType(elementType);
527         OutDts(")");
528     } else {
529         GenType(elementType);
530     }
531     OutDts("[]");
532 }
533 
GenLiteral(const ir::Literal * literal)534 void TSDeclGen::GenLiteral(const ir::Literal *literal)
535 {
536     if (literal->IsNumberLiteral()) {
537         const auto number = literal->AsNumberLiteral()->Number();
538         if (number.IsInt()) {
539             OutDts(std::to_string(number.GetInt()));
540             return;
541         }
542         if (number.IsLong()) {
543             OutDts(std::to_string(number.GetLong()));
544             return;
545         }
546         if (number.IsFloat()) {
547             OutDts(std::to_string(number.GetFloat()));
548             return;
549         }
550         if (number.IsDouble()) {
551             OutDts(std::to_string(number.GetDouble()));
552             return;
553         }
554         LogError(diagnostic::UNEXPECTED_NUMBER_LITERAL_TYPE, {}, literal->Start());
555     } else if (literal->IsStringLiteral()) {
556         const auto string = literal->AsStringLiteral()->ToString();
557         importSet_.insert(string);
558         OutDts("\"" + string + "\"");
559     } else if (literal->IsBooleanLiteral()) {
560         OutDts(literal->AsBooleanLiteral()->ToString());
561     } else {
562         LogError(diagnostic::UNSUPPORTED_LITERAL_TYPE, {}, literal->Start());
563     }
564 }
565 
ProcessParamDefaultToMap(const ir::Statement * stmt)566 void TSDeclGen::ProcessParamDefaultToMap(const ir::Statement *stmt)
567 {
568     if (!stmt->IsVariableDeclaration()) {
569         return;
570     }
571     GenSeparated(
572         stmt->AsVariableDeclaration()->Declarators(),
573         [this](ir::VariableDeclarator *declarator) {
574             const auto *init = declarator->Init();
575             if (init != nullptr && init->IsConditionalExpression() &&
576                 init->AsConditionalExpression()->Test()->IsBinaryExpression()) {
577                 const auto *left = init->AsConditionalExpression()->Test()->AsBinaryExpression()->Left();
578                 if (left->IsIdentifier()) {
579                     const auto varName = GetKeyIdent(declarator->Id())->Name();
580                     paramDefaultMap_.insert({left->AsIdentifier()->Name(), varName});
581                 }
582             }
583         },
584         "");
585 }
586 
GetFuncSignature(const checker::ETSFunctionType * etsFunctionType,const ir::MethodDefinition * methodDef)587 const checker::Signature *TSDeclGen::GetFuncSignature(const checker::ETSFunctionType *etsFunctionType,
588                                                       const ir::MethodDefinition *methodDef)
589 {
590     if (etsFunctionType->IsETSArrowType()) {
591         return etsFunctionType->ArrowSignature();
592     }
593     if (methodDef != nullptr) {
594         auto methDefFunc = methodDef->Function();
595         return methDefFunc != nullptr ? methDefFunc->Signature() : nullptr;
596     }
597     if (etsFunctionType->CallSignatures().size() != 1) {
598         const auto loc = methodDef != nullptr ? methodDef->Start() : lexer::SourcePosition();
599         LogError(diagnostic::NOT_OVERLOAD_SUPPORT, {}, loc);
600     }
601     return etsFunctionType->CallSignatures()[0];
602 }
603 
ProcessParameterName(varbinder::LocalVariable * param)604 void TSDeclGen::ProcessParameterName(varbinder::LocalVariable *param)
605 {
606     const auto *paramDeclNode = param->Declaration()->Node();
607     const std::string prefix = "gensym%%_";
608 
609     if (!paramDefaultMap_.empty() && paramDefaultMap_.find(param->Name()) != paramDefaultMap_.end()) {
610         OutDts(paramDefaultMap_[param->Name()]);
611         paramDefaultMap_.erase(param->Name());
612     } else if (param->Name().Is("=t")) {
613         OutDts("this");
614     } else if (paramDeclNode->IsETSParameterExpression() && paramDeclNode->AsETSParameterExpression()->IsOptional() &&
615                paramDeclNode->AsETSParameterExpression()->Name().StartsWith(prefix)) {
616         OutDts("arg", param->Name().Mutf8().substr(prefix.size()));
617     } else {
618         OutDts(param->Name());
619     }
620 }
621 
ProcessFuncParameter(varbinder::LocalVariable * param)622 void TSDeclGen::ProcessFuncParameter(varbinder::LocalVariable *param)
623 {
624     if (std::string(param->Name()).find("<property>") != std::string::npos) {
625         return;
626     }
627 
628     ProcessParameterName(param);
629 
630     const auto *paramType = param->TsType();
631     const auto *paramDeclNode = param->Declaration()->Node();
632 
633     if (!paramDeclNode->IsETSParameterExpression()) {
634         if (param->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
635             OutDts("?");
636         }
637         OutDts(": ");
638         GenType(paramType);
639         return;
640     }
641 
642     const auto *expr = paramDeclNode->AsETSParameterExpression();
643     OutDts(expr->IsOptional() ? "?" : "");
644     OutDts(": ");
645 
646     const auto *typeAnnotation = expr->TypeAnnotation();
647     if (typeAnnotation != nullptr) {
648         if (expr->IsOptional()) {
649             ProcessTypeAnnotationType(typeAnnotation);
650             return;
651         }
652         ProcessTypeAnnotationType(typeAnnotation, paramType);
653         return;
654     }
655     OutDts("ESObject");
656 }
657 
ProcessFuncParameters(const checker::Signature * sig)658 void TSDeclGen::ProcessFuncParameters(const checker::Signature *sig)
659 {
660     GenSeparated(sig->Params(), [this](varbinder::LocalVariable *param) { ProcessFuncParameter(param); });
661 }
662 
GenFunctionType(const checker::ETSFunctionType * etsFunctionType,const ir::MethodDefinition * methodDef)663 void TSDeclGen::GenFunctionType(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef)
664 {
665     const bool isConstructor = methodDef != nullptr ? methodDef->IsConstructor() : false;
666     const bool isSetter = methodDef != nullptr ? methodDef->Kind() == ir::MethodDefinitionKind::SET : false;
667     // CC-OFFNXT(G.FMT.14-CPP) project code style
668     const auto *sig = GetFuncSignature(etsFunctionType, methodDef);
669     ES2PANDA_ASSERT(sig != nullptr);
670     if (sig->HasFunction()) {
671         GenTypeParameters(sig->Function()->TypeParams());
672         const auto *funcBody = sig->Function()->Body();
673         if (funcBody != nullptr && funcBody->IsBlockStatement() &&
674             !funcBody->AsBlockStatement()->Statements().empty()) {
675             for (const auto *statement : funcBody->AsBlockStatement()->Statements()) {
676                 ProcessParamDefaultToMap(statement);
677             }
678         }
679     }
680     OutDts("(");
681 
682     ProcessFuncParameters(sig);
683 
684     const auto *sigInfo = sig->GetSignatureInfo();
685     if (sigInfo->restVar != nullptr) {
686         if (!sig->Params().empty()) {
687             OutDts(", ");
688         }
689         OutDts("...", sigInfo->restVar->Name().Mutf8(), ": ");
690         GenType(sigInfo->restVar->TsType());
691     }
692     OutDts(")");
693     if (!isSetter && !isConstructor) {
694         OutDts(methodDef != nullptr ? ": " : " => ");
695         if (!sig->HasFunction()) {
696             GenType(sig->ReturnType());
697             return;
698         }
699         ProcessFunctionReturnType(sig);
700     }
701 }
702 
SplitUnionTypes(std::string & unionTypeString)703 void TSDeclGen::SplitUnionTypes(std::string &unionTypeString)
704 {
705     std::vector<std::string> result;
706     std::string currentType;
707 
708     for (char c : unionTypeString) {
709         if (std::isspace(c)) {
710             continue;
711         }
712         if (c == '|') {
713             if (!currentType.empty()) {
714                 importSet_.insert(currentType);
715                 currentType.clear();
716             }
717         } else {
718             currentType += c;
719         }
720     }
721     if (!currentType.empty()) {
722         importSet_.insert(currentType);
723     }
724 }
725 
ProcessFunctionReturnType(const checker::Signature * sig)726 void TSDeclGen::ProcessFunctionReturnType(const checker::Signature *sig)
727 {
728     const auto returnStatements = sig->Function()->ReturnStatements();
729     if (!returnStatements.empty() && returnStatements.size() == 1 && returnStatements.at(0)->Argument() != nullptr &&
730         returnStatements.at(0)->Argument()->IsETSNewClassInstanceExpression()) {
731         auto newExpr = returnStatements.at(0)->Argument()->AsETSNewClassInstanceExpression();
732         if (newExpr->GetTypeRef() != nullptr && newExpr->GetTypeRef()->IsETSTypeReference()) {
733             ProcessETSTypeReferenceType(newExpr->GetTypeRef()->AsETSTypeReference(), sig->ReturnType());
734             return;
735         }
736     }
737 
738     const auto returnTypeAnnotation = sig->Function()->ReturnTypeAnnotation();
739     if (returnTypeAnnotation != nullptr) {
740         ProcessTypeAnnotationType(returnTypeAnnotation, sig->ReturnType());
741         return;
742     }
743 
744     if (sig->HasSignatureFlag(checker::SignatureFlags::SETTER)) {
745         const auto param = sig->Function()->Params();
746         if (!param.empty() && param.size() == 1 && param.at(0)->IsETSParameterExpression() &&
747             param.at(0)->AsETSParameterExpression()->Ident()->TypeAnnotation() != nullptr) {
748             ProcessTypeAnnotationType(param.at(0)->AsETSParameterExpression()->Ident()->TypeAnnotation(),
749                                       sig->Params()[0]->TsType());
750             return;
751         }
752         if (!sig->Params().empty() && sig->Params().size() == 1) {
753             GenType(sig->Params()[0]->TsType());
754             return;
755         }
756     }
757 
758     std::string typeStr = sig->ReturnType()->ToString();
759     if (declgenOptions_.isIsolatedDeclgen && typeStr.find(ERROR_TYPE) != std::string::npos) {
760         typeStr = sig->Function()->GetIsolatedDeclgenReturnType();
761         OutDts(typeStr);
762         SplitUnionTypes(typeStr);
763         return;
764     }
765     GenType(sig->ReturnType());
766 }
767 
GenUnionType(const checker::ETSUnionType * unionType)768 void TSDeclGen::GenUnionType(const checker::ETSUnionType *unionType)
769 {
770     state_.inUnionBodyStack.push(true);
771     std::vector<checker::Type *> filteredTypes = FilterUnionTypes(unionType->ConstituentTypes());
772     GenSeparated(
773         filteredTypes, [this](checker::Type *arg) { GenType(arg); }, " | ");
774     state_.inUnionBodyStack.pop();
775 }
776 
777 template <class UnionType>
FilterUnionTypes(const ArenaVector<UnionType * > & originTypes)778 std::vector<UnionType *> TSDeclGen::FilterUnionTypes(const ArenaVector<UnionType *> &originTypes)
779 {
780     if (originTypes.empty()) {
781         return {};
782     }
783     bool hasNumber = false;
784     bool hasString = false;
785     std::vector<UnionType *> filteredTypes;
786     for (auto originType : originTypes) {
787         std::string typeStr = originType->ToString();
788         if constexpr (std::is_same_v<UnionType, ir::TypeNode>) {
789             if (originType->IsTSThisType()) {
790                 filteredTypes.push_back(originType);
791                 continue;
792             }
793             auto type = originType->GetType(checker_);
794             if (type == nullptr) {
795                 continue;
796             }
797             typeStr = type->ToString();
798             typeStr[0] = std::toupper(typeStr[0]);
799         }
800         if (stringTypes_.count(typeStr) != 0U) {
801             if (hasString) {
802                 continue;
803             }
804             hasString = true;
805         } else if (numberTypes_.count(typeStr) != 0U) {
806             if (hasNumber) {
807                 continue;
808             }
809             hasNumber = true;
810         }
811         filteredTypes.push_back(originType);
812     }
813     return filteredTypes;
814 }
815 
GenTupleType(const checker::ETSTupleType * tupleType)816 void TSDeclGen::GenTupleType(const checker::ETSTupleType *tupleType)
817 {
818     OutDts("[");
819     GenSeparated(
820         tupleType->GetTupleTypesList(), [this](checker::Type *arg) { GenType(arg); }, " , ");
821     OutDts("]");
822 }
823 
HandleSpecificObjectTypes(const checker::ETSObjectType * objectType)824 bool TSDeclGen::HandleSpecificObjectTypes(const checker::ETSObjectType *objectType)
825 {
826     if (objectType->IsETSStringType()) {
827         OutDts("string");
828         return true;
829     }
830     if (objectType->IsETSBigIntType()) {
831         OutDts("bigint");
832         return true;
833     }
834     if (objectType->IsETSUnboxableObject()) {
835         OutDts("number");  // NOTE(ivagin): create precise builtin type
836         return true;
837     }
838     if (objectType->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL)) {
839         const auto *invoke = objectType->GetFunctionalInterfaceInvokeType();
840         ES2PANDA_ASSERT(invoke && invoke->IsETSFunctionType());
841         GenType(invoke);
842         return true;
843     }
844     if (objectType->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC)) {
845         OutDts("any");
846         return true;
847     }
848     return false;
849 }
850 
HandleTypeArgument(checker::Type * arg,const std::string & typeStr)851 void TSDeclGen::HandleTypeArgument(checker::Type *arg, const std::string &typeStr)
852 {
853     if (typeStr == "Promise" && arg != nullptr && arg->HasTypeFlag(checker::TypeFlag::ETS_UNDEFINED)) {
854         OutDts("void");
855     } else if (arg != nullptr) {
856         if (!state_.currentTypeAliasName.empty() && !arg->HasTypeFlag(checker::TypeFlag::ETS_TYPE_PARAMETER)) {
857             OutDts(state_.currentTypeAliasName);
858             if (state_.currentTypeParams != nullptr) {
859                 importSet_.insert(state_.currentTypeParams->Params()[0]->Name()->Name().Mutf8());
860                 OutDts("<");
861                 OutDts(state_.currentTypeParams->Params()[0]->Name()->Name());
862                 OutDts(">");
863             }
864         } else {
865             GenType(arg);
866         }
867     }
868 }
869 
GenObjectType(const checker::ETSObjectType * objectType)870 void TSDeclGen::GenObjectType(const checker::ETSObjectType *objectType)
871 {
872     if (HandleSpecificObjectTypes(objectType)) {
873         return;
874     }
875     std::string typeStr = objectType->Name().Mutf8();
876     if (objectType->Name().Empty()) {
877         LogWarning(diagnostic::EMPTY_TYPE_NAME);
878         OutDts("ESObject");
879     } else {
880         if (typeStr == "Exception" || typeStr == "NullPointerError") {
881             OutDts("Error");
882         } else if (size_t partialPos = typeStr.find("$partial"); partialPos != std::string::npos) {
883             OutDts("Partial<", typeStr.substr(0, partialPos), ">");
884         } else {
885             OutDts(typeStr);
886         }
887         importSet_.insert(typeStr);
888         indirectDependencyObjects_.insert(typeStr);
889     }
890 
891     const auto &typeArgs = objectType->TypeArguments();
892     if (typeArgs.empty()) {
893         return;
894     }
895 
896     OutDts("<");
897     GenSeparated(typeArgs, [this, typeStr](checker::Type *arg) { HandleTypeArgument(arg, typeStr); });
898     OutDts(">");
899 }
900 
GenTypeParameters(const ir::TSTypeParameterDeclaration * typeParams)901 void TSDeclGen::GenTypeParameters(const ir::TSTypeParameterDeclaration *typeParams)
902 {
903     if (typeParams != nullptr) {
904         OutDts("<");
905         GenSeparated(typeParams->Params(), [this](ir::TSTypeParameter *param) {
906             OutDts(param->Name()->Name());
907             auto *constraint = param->Constraint();
908             if (constraint != nullptr) {
909                 OutDts(" extends ");
910                 GenType(constraint->GetType(checker_));
911             }
912             auto *defaultType = param->DefaultType();
913             if (defaultType != nullptr) {
914                 OutDts(" = ");
915                 defaultType->IsETSTypeReference() ? ProcessETSTypeReferenceType(defaultType->AsETSTypeReference())
916                                                   : GenType(defaultType->TsType());
917             }
918         });
919         OutDts(">");
920     }
921 }
922 
GenExport(const ir::Identifier * symbol)923 void TSDeclGen::GenExport(const ir::Identifier *symbol)
924 {
925     const auto symbolName = symbol->Name().Mutf8();
926     OutDts("export {", symbolName, "};");
927     OutEndlDts();
928     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
929         OutDts("exports.", symbolName, " = ", symbolName, ";");
930     }
931     OutEndlDts();
932 }
933 
GenExport(const ir::Identifier * symbol,const std::string & alias)934 void TSDeclGen::GenExport(const ir::Identifier *symbol, const std::string &alias)
935 {
936     const auto symbolName = symbol->Name().Mutf8();
937     OutDts("export {", symbolName, " as ", alias, "};");
938     OutEndlDts();
939     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
940         OutDts("exports.", alias, " = ", symbolName, ";");
941     }
942     OutEndlDts();
943 }
944 
GenDefaultExport(const ir::Identifier * symbol)945 void TSDeclGen::GenDefaultExport(const ir::Identifier *symbol)
946 {
947     const auto symbolName = symbol->Name().Mutf8();
948     OutDts("export default ", symbolName, ";");
949     OutEndlDts();
950     if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
951         OutDts("exports.default = ", symbolName, ";");
952     }
953     OutEndlDts();
954 }
955 
ShouldEmitDeclarationSymbol(const ir::Identifier * symbol)956 bool TSDeclGen::ShouldEmitDeclarationSymbol(const ir::Identifier *symbol)
957 {
958     if (declgenOptions_.exportAll) {
959         return true;
960     }
961     if (symbol->Parent()->IsExported() || symbol->Parent()->IsDefaultExported()) {
962         return true;
963     }
964     if (state_.isDeclareNamespace) {
965         return true;
966     }
967     if (state_.isDeclareNamespace) {
968         return true;
969     }
970     if (indirectDependencyObjects_.find(symbol->Name().Mutf8()) != indirectDependencyObjects_.end()) {
971         classNode_.isIndirect = true;
972         return true;
973     }
974 
975     return false;
976 }
977 
978 template <class T>
GenModifier(const T * node,bool isProp)979 void TSDeclGen::GenModifier(const T *node, bool isProp)
980 {
981     if (state_.inInterface) {
982         return;
983     }
984 
985     if (state_.inNamespace && isProp && !state_.isClassInNamespace) {
986         OutDts(node->IsConst() ? "const " : "let ");
987         return;
988     }
989     if (state_.inNamespace && !isProp && !state_.isClassInNamespace) {
990         OutDts("function ");
991         return;
992     }
993     if (node->IsPublic()) {
994         OutDts("public ");
995     } else if (node->IsPrivate()) {
996         OutDts("private ");
997     } else if (node->IsProtected()) {
998         OutDts("protected ");
999     }
1000     if (node->IsStatic()) {
1001         OutDts("static ");
1002     }
1003     if (node->IsReadonly() && isProp) {
1004         OutDts("readonly ");
1005     }
1006 }
1007 
RemoveModuleExtensionName(const std::string & filepath)1008 std::string TSDeclGen::RemoveModuleExtensionName(const std::string &filepath)
1009 {
1010     for (const auto &extension : extensions_) {
1011         auto pos = filepath.rfind(extension);
1012         if (pos != std::string::npos && pos == filepath.length() - extension.length()) {
1013             return filepath.substr(0, pos);
1014         }
1015     }
1016     return filepath;
1017 }
1018 
1019 template <class T>
GenAnnotations(const T * node)1020 void TSDeclGen::GenAnnotations(const T *node)
1021 {
1022     if (node == nullptr) {
1023         return;
1024     }
1025     GenSeparated(
1026         node->Annotations(),
1027         [this](ir::AnnotationUsage *anno) {
1028             if (annotationList_.count(anno->GetBaseName()->Name().Mutf8()) == 0U) {
1029                 return;
1030             }
1031             if (!state_.inGlobalClass && (state_.inClass || state_.inInterface)) {
1032                 ProcessIndent();
1033             }
1034             importSet_.insert(anno->GetBaseName()->Name().Mutf8());
1035             OutDts("@", anno->GetBaseName()->Name());
1036             GenAnnotationProperties(anno);
1037             OutEndlDts();
1038         },
1039         "");
1040 }
1041 
GenAnnotationProperties(const ir::AnnotationUsage * anno)1042 void TSDeclGen::GenAnnotationProperties(const ir::AnnotationUsage *anno)
1043 {
1044     if (anno->Properties().empty()) {
1045         return;
1046     }
1047 
1048     const auto &properties = anno->Properties();
1049     if (properties.size() == 1 && properties.at(0)->IsClassProperty() &&
1050         properties.at(0)->AsClassProperty()->Id() != nullptr &&
1051         properties.at(0)->AsClassProperty()->Id()->Name() == compiler::Signatures::ANNOTATION_KEY_VALUE) {
1052         OutDts("(");
1053         if (properties.at(0)->AsClassProperty()->Value() != nullptr) {
1054             GenAnnotationPropertyValue(properties.at(0)->AsClassProperty()->Value());
1055         }
1056         OutDts(")");
1057         return;
1058     }
1059 
1060     OutDts("({");
1061     OutEndlDts();
1062     for (auto *prop : properties) {
1063         ProcessIndent();
1064         ES2PANDA_ASSERT(prop->AsClassProperty()->Id() != nullptr);
1065         OutDts(prop->AsClassProperty()->Id()->Name());
1066         OutDts(": ");
1067         if (prop->AsClassProperty()->Value() != nullptr) {
1068             GenAnnotationPropertyValue(prop->AsClassProperty()->Value());
1069         }
1070         if (prop != properties.back()) {
1071             OutDts(",");
1072         }
1073         OutEndlDts();
1074     }
1075     OutDts("})");
1076 }
1077 
GenAnnotationPropertyValue(ir::Expression * propValue)1078 void TSDeclGen::GenAnnotationPropertyValue(ir::Expression *propValue)
1079 {
1080     if (propValue->IsLiteral()) {
1081         GenLiteral(propValue->AsLiteral());
1082     } else if (propValue->IsArrayExpression()) {
1083         OutDts("[");
1084         GenSeparated(propValue->AsArrayExpression()->Elements(),
1085                      [this](ir::Expression *element) { GenAnnotationPropertyValue(element); });
1086         OutDts("]");
1087     } else {
1088         GenType(propValue->Check(checker_));
1089     }
1090 }
1091 
GenImportDeclaration(const ir::ETSImportDeclaration * importDeclaration)1092 void TSDeclGen::GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration)
1093 {
1094     DebugPrint("GenImportDeclaration");
1095     if (importDeclaration->IsPureDynamic()) {
1096         return;
1097     }
1098     const auto &specifiers = importDeclaration->Specifiers();
1099     if (specifiers.empty()) {
1100         return;
1101     }
1102     auto source = importDeclaration->Source()->Str().Mutf8();
1103     source = RemoveModuleExtensionName(source);
1104     const auto specifierFirst = specifiers[0];
1105     bool isTypeKind = importDeclaration->IsTypeKind();
1106     if (specifierFirst->IsImportNamespaceSpecifier()) {
1107         GenNamespaceImport(specifierFirst, source);
1108     } else if (specifierFirst->IsImportDefaultSpecifier()) {
1109         GenDefaultImport(specifierFirst, source, isTypeKind);
1110     } else if (specifierFirst->IsImportSpecifier()) {
1111         GenNamedImports(importDeclaration, specifiers, isTypeKind);
1112     }
1113 }
1114 
GenNamespaceImport(const ir::AstNode * specifier,const std::string & source)1115 void TSDeclGen::GenNamespaceImport(const ir::AstNode *specifier, const std::string &source)
1116 {
1117     const auto local = specifier->AsImportNamespaceSpecifier()->Local()->Name();
1118     OutTs("import * as ", local, " from \"", source, "\";");
1119     OutEndlTs();
1120     if (importSet_.find(local.Mutf8()) == importSet_.end()) {
1121         return;
1122     }
1123     OutDts("import * as ", local, " from \"", source, "\";");
1124     OutEndlDts();
1125 }
1126 
GenDefaultImport(const ir::AstNode * specifier,const std::string & source,bool isTypeKind)1127 void TSDeclGen::GenDefaultImport(const ir::AstNode *specifier, const std::string &source, bool isTypeKind)
1128 {
1129     auto importDefaultSpecifier = specifier->AsImportDefaultSpecifier();
1130     auto variable = importDefaultSpecifier->Local()->Variable();
1131     const auto local = importDefaultSpecifier->Local()->Name();
1132     bool isTypeDeclaration = false;
1133     if (variable != nullptr && variable->Declaration() != nullptr && variable->Declaration()->Node() != nullptr) {
1134         auto *node = variable->Declaration()->Node();
1135         isTypeDeclaration = node->IsTSTypeAliasDeclaration() || node->IsTSInterfaceDeclaration();
1136     }
1137     if (!isTypeKind && !isTypeDeclaration) {
1138         OutTs("import ", local, " from \"", source, "\";");
1139         OutEndlTs();
1140     }
1141 
1142     if (importSet_.find(local.Mutf8()) == importSet_.end()) {
1143         return;
1144     }
1145     OutDts(isTypeKind ? "import type " : "import ", local, " from \"", source, "\";");
1146     OutEndlDts();
1147 }
1148 
GenNamedImports(const ir::ETSImportDeclaration * importDeclaration,const ArenaVector<ir::AstNode * > & specifiers,bool isTypeKind)1149 void TSDeclGen::GenNamedImports(const ir::ETSImportDeclaration *importDeclaration,
1150                                 const ArenaVector<ir::AstNode *> &specifiers, bool isTypeKind)
1151 {
1152     if (specifiers.empty()) {
1153         return;
1154     }
1155     std::vector<ir::AstNode *> interfaceSpecifiers;
1156     std::vector<ir::AstNode *> normalSpecifiers;
1157     SeparateInterfaceSpecifiers(specifiers, interfaceSpecifiers, normalSpecifiers);
1158 
1159     if (!isTypeKind) {
1160         GenTsImportStatement(normalSpecifiers, importDeclaration);
1161     }
1162 
1163     auto importSpecifiers = FilterValidImportSpecifiers(specifiers);
1164     GenDtsImportStatement(importSpecifiers, importDeclaration, isTypeKind);
1165 }
1166 
GenTsImportStatement(std::vector<ir::AstNode * > & specifiers,const ir::ETSImportDeclaration * importDeclaration,bool isInterface)1167 void TSDeclGen::GenTsImportStatement(std::vector<ir::AstNode *> &specifiers,
1168                                      const ir::ETSImportDeclaration *importDeclaration, bool isInterface)
1169 {
1170     if (specifiers.empty()) {
1171         return;
1172     }
1173 
1174     auto source = importDeclaration->Source()->Str().Mutf8();
1175     source = RemoveModuleExtensionName(source);
1176     OutTs(isInterface ? "import type" : "import", " { ");
1177 
1178     GenSeparated(
1179         specifiers,
1180         [this, importDeclaration](ir::AstNode *specifier) { GenSingleNamedImport(specifier, importDeclaration, true); },
1181         ", ", true, false);
1182 
1183     OutTs(" } from \"", source, "\";\n");
1184 }
1185 
GenDtsImportStatement(std::vector<ir::AstNode * > & specifiers,const ir::ETSImportDeclaration * importDeclaration,bool isTypeKind)1186 void TSDeclGen::GenDtsImportStatement(std::vector<ir::AstNode *> &specifiers,
1187                                       const ir::ETSImportDeclaration *importDeclaration, bool isTypeKind)
1188 {
1189     if (specifiers.empty()) {
1190         return;
1191     }
1192 
1193     auto source = importDeclaration->Source()->Str().Mutf8();
1194     source = RemoveModuleExtensionName(source);
1195     OutDts(isTypeKind ? "import type" : "import", " { ");
1196 
1197     GenSeparated(
1198         specifiers,
1199         [this, importDeclaration](ir::AstNode *specifier) { GenSingleNamedImport(specifier, importDeclaration); },
1200         ", ");
1201 
1202     OutDts(" } from \"", source, "\";\n");
1203 }
1204 
GenSingleNamedImport(ir::AstNode * specifier,const ir::ETSImportDeclaration * importDeclaration,bool isGlueCode)1205 void TSDeclGen::GenSingleNamedImport(ir::AstNode *specifier, const ir::ETSImportDeclaration *importDeclaration,
1206                                      bool isGlueCode)
1207 {
1208     if (!specifier->IsImportSpecifier()) {
1209         LogError(diagnostic::IMPORT_SPECIFIERS_SUPPORT, {}, importDeclaration->Start());
1210     }
1211     const auto local = specifier->AsImportSpecifier()->Local()->Name().Mutf8();
1212     const auto imported = specifier->AsImportSpecifier()->Imported()->Name().Mutf8();
1213     if (local != imported) {
1214         isGlueCode ? OutTs(imported, " as ", local) : OutDts(imported, " as ", local);
1215     } else {
1216         isGlueCode ? OutTs(local) : OutDts(local);
1217     }
1218 }
1219 
FilterValidImportSpecifiers(const ArenaVector<ir::AstNode * > & specifiers)1220 std::vector<ir::AstNode *> TSDeclGen::FilterValidImportSpecifiers(const ArenaVector<ir::AstNode *> &specifiers)
1221 {
1222     std::vector<ir::AstNode *> importSpecifiers;
1223     for (auto specifier : specifiers) {
1224         if (specifier->AsImportSpecifier()->IsRemovable()) {
1225             continue;
1226         }
1227         const auto local = specifier->AsImportSpecifier()->Local()->Name().Mutf8();
1228         if (importSet_.find(local) != importSet_.end()) {
1229             importSpecifiers.push_back(specifier);
1230         }
1231     }
1232     return importSpecifiers;
1233 }
1234 
GenReExportDeclaration(const ir::ETSReExportDeclaration * reExportDeclaration)1235 void TSDeclGen::GenReExportDeclaration(const ir::ETSReExportDeclaration *reExportDeclaration)
1236 {
1237     DebugPrint("GenReExportDeclaration");
1238     auto importDeclaration = reExportDeclaration->GetETSImportDeclarations();
1239     if (importDeclaration->IsPureDynamic()) {
1240         return;
1241     }
1242     const auto &specifiers = importDeclaration->Specifiers();
1243 
1244     if (specifiers.size() == 1 && GenNamespaceReExportDeclaration(specifiers[0], importDeclaration)) {
1245         return;
1246     }
1247 
1248     bool isTypeKind = reExportDeclaration->IsExportedType();
1249     std::vector<ir::AstNode *> interfaceSpecifiers;
1250     std::vector<ir::AstNode *> normalSpecifiers;
1251     SeparateInterfaceSpecifiers(specifiers, interfaceSpecifiers, normalSpecifiers);
1252 
1253     GenDtsReExportStatement(specifiers, importDeclaration, isTypeKind);
1254 
1255     if (!isTypeKind) {
1256         GenTsReExportStatement(normalSpecifiers, importDeclaration);
1257     }
1258 }
1259 
GenNamespaceReExportDeclaration(const ir::AstNode * specifier,const ir::ETSImportDeclaration * importDeclaration)1260 bool TSDeclGen::GenNamespaceReExportDeclaration(const ir::AstNode *specifier,
1261                                                 const ir::ETSImportDeclaration *importDeclaration)
1262 {
1263     if (specifier->IsImportNamespaceSpecifier()) {
1264         const auto local = specifier->AsImportNamespaceSpecifier()->Local()->Name();
1265         if (local.Empty()) {
1266             auto source = importDeclaration->Source()->Str().Mutf8();
1267             source = RemoveModuleExtensionName(source);
1268             OutDts("export * from \"", source, "\";\n");
1269             OutTs("export * from \"", source, "\";\n");
1270             return true;
1271         }
1272     }
1273     return false;
1274 }
1275 
SeparateInterfaceSpecifiers(const ArenaVector<ir::AstNode * > & specifiers,std::vector<ir::AstNode * > & interfaceSpecifiers,std::vector<ir::AstNode * > & normalSpecifiers)1276 void TSDeclGen::SeparateInterfaceSpecifiers(const ArenaVector<ir::AstNode *> &specifiers,
1277                                             std::vector<ir::AstNode *> &interfaceSpecifiers,
1278                                             std::vector<ir::AstNode *> &normalSpecifiers)
1279 {
1280     for (auto *specifier : specifiers) {
1281         if (!specifier->IsImportSpecifier()) {
1282             continue;
1283         }
1284         auto importSpecifier = specifier->AsImportSpecifier();
1285         auto variable = importSpecifier->Imported()->Variable();
1286         bool isTypeDeclaration = false;
1287         if (variable != nullptr && variable->Declaration() != nullptr && variable->Declaration()->Node() != nullptr) {
1288             auto *node = variable->Declaration()->Node();
1289             isTypeDeclaration = node->IsTSTypeAliasDeclaration() || node->IsTSInterfaceDeclaration();
1290         }
1291         if (isTypeDeclaration) {
1292             interfaceSpecifiers.push_back(specifier);
1293         } else {
1294             normalSpecifiers.push_back(specifier);
1295         }
1296     }
1297 }
1298 
GenSingleNamedReExport(ir::AstNode * specifier,const ir::ETSImportDeclaration * importDeclaration,bool isGlueCode)1299 void TSDeclGen::GenSingleNamedReExport(ir::AstNode *specifier, const ir::ETSImportDeclaration *importDeclaration,
1300                                        bool isGlueCode)
1301 {
1302     if (specifier->IsImportSpecifier()) {
1303         const auto local = specifier->AsImportSpecifier()->Local()->Name().Mutf8();
1304         const auto imported = specifier->AsImportSpecifier()->Imported()->Name().Mutf8();
1305         importSet_.insert(local);
1306         if (local != imported) {
1307             isGlueCode ? OutTs(imported, " as ", local) : OutDts(imported, " as ", local);
1308         } else {
1309             isGlueCode ? OutTs(local) : OutDts(local);
1310         }
1311     } else if (specifier->IsImportNamespaceSpecifier()) {
1312         const auto local = specifier->AsImportNamespaceSpecifier()->Local()->Name().Mutf8();
1313         importSet_.insert(local);
1314         isGlueCode ? OutTs(local) : OutDts(local);
1315     } else {
1316         LogError(diagnostic::IMPORT_SPECIFIERS_SUPPORT, {}, importDeclaration->Start());
1317     }
1318 }
1319 
GenDtsReExportStatement(const ArenaVector<ir::AstNode * > & specifiers,const ir::ETSImportDeclaration * importDeclaration,bool isTypeKind)1320 void TSDeclGen::GenDtsReExportStatement(const ArenaVector<ir::AstNode *> &specifiers,
1321                                         const ir::ETSImportDeclaration *importDeclaration, bool isTypeKind)
1322 {
1323     if (specifiers.empty()) {
1324         return;
1325     }
1326 
1327     auto source = importDeclaration->Source()->Str().Mutf8();
1328     source = RemoveModuleExtensionName(source);
1329     OutDts(isTypeKind ? "export type" : "export", " { ");
1330 
1331     GenSeparated(
1332         specifiers,
1333         [this, importDeclaration](ir::AstNode *specifier) { GenSingleNamedReExport(specifier, importDeclaration); },
1334         ", ");
1335 
1336     OutDts(" } from \"", source, "\";\n");
1337 }
1338 
GenTsReExportStatement(const std::vector<ir::AstNode * > & specifiers,const ir::ETSImportDeclaration * importDeclaration,bool isInterface)1339 void TSDeclGen::GenTsReExportStatement(const std::vector<ir::AstNode *> &specifiers,
1340                                        const ir::ETSImportDeclaration *importDeclaration, bool isInterface)
1341 {
1342     if (specifiers.empty()) {
1343         return;
1344     }
1345     auto source = importDeclaration->Source()->Str().Mutf8();
1346     source = RemoveModuleExtensionName(source);
1347     OutTs(isInterface ? "export type" : "export", " { ");
1348 
1349     GenSeparated(
1350         specifiers,
1351         [this, importDeclaration](ir::AstNode *specifier) {
1352             GenSingleNamedReExport(specifier, importDeclaration, true);
1353         },
1354         ", ", true, false);
1355 
1356     OutTs(" } from \"", source, "\";\n");
1357 }
1358 
ReplaceETSGLOBAL(const std::string & typeName)1359 std::string TSDeclGen::ReplaceETSGLOBAL(const std::string &typeName)
1360 {
1361     if (typeName.empty()) {
1362         return globalDesc_;
1363     }
1364     const std::string target = "ETSGLOBAL";
1365     std::size_t pos = globalDesc_.find(target);
1366     if (pos != std::string::npos) {
1367         return globalDesc_.substr(0, pos) + typeName + globalDesc_.substr(pos + target.length());
1368     }
1369     return globalDesc_;
1370 }
1371 
ProcessTSQualifiedName(const ir::ETSTypeReference * typeReference)1372 bool TSDeclGen::ProcessTSQualifiedName(const ir::ETSTypeReference *typeReference)
1373 {
1374     if (typeReference->Part()->Name()->IsTSQualifiedName() &&
1375         typeReference->Part()->Name()->AsTSQualifiedName()->Name() != nullptr) {
1376         const auto qualifiedName = typeReference->Part()->Name()->AsTSQualifiedName()->Name().Mutf8();
1377         std::istringstream stream(qualifiedName);
1378         std::string firstSegment;
1379         if (std::getline(stream, firstSegment, '.') && stdlibNamespaceList_.count(firstSegment) != 0U) {
1380             OutDts("ESObject");
1381             return true;
1382         }
1383         importSet_.insert(firstSegment);
1384         indirectDependencyObjects_.insert(firstSegment);
1385         std::string segment;
1386         while (std::getline(stream, segment, '.')) {
1387             importSet_.insert(segment);
1388             indirectDependencyObjects_.insert(segment);
1389         }
1390         OutDts(qualifiedName);
1391         return true;
1392     }
1393     return false;
1394 }
1395 
ProcessETSTypeReferenceType(const ir::ETSTypeReference * typeReference,const checker::Type * checkerType)1396 void TSDeclGen::ProcessETSTypeReferenceType(const ir::ETSTypeReference *typeReference, const checker::Type *checkerType)
1397 {
1398     auto typePart = typeReference->Part();
1399     auto partName = typePart->GetIdent()->Name().Mutf8();
1400     if (partName == "Type" || partName == "Function0") {
1401         OutDts("ESObject");
1402         return;
1403     }
1404     importSet_.insert(partName);
1405     if (typePart->TypeParams() != nullptr && typePart->TypeParams()->IsTSTypeParameterInstantiation()) {
1406         indirectDependencyObjects_.insert(partName);
1407         if (partName == "FixedArray") {
1408             GenSeparated(typePart->TypeParams()->Params(),
1409                          [this](ir::TypeNode *param) { ProcessTypeAnnotationType(param, param->GetType(checker_)); });
1410             OutDts("[]");
1411             return;
1412         }
1413         OutDts(partName);
1414         OutDts("<");
1415         GenSeparated(typePart->TypeParams()->Params(),
1416                      [this](ir::TypeNode *param) { ProcessTypeAnnotationType(param, param->GetType(checker_)); });
1417         OutDts(">");
1418     } else if (ProcessTSQualifiedName(typeReference)) {
1419         return;
1420     } else if (checkerType != nullptr && checkerType->IsETSFunctionType()) {
1421         indirectDependencyObjects_.insert(partName);
1422         OutDts(partName);
1423     } else {
1424         GenPartName(partName);
1425         indirectDependencyObjects_.insert(partName);
1426         OutDts(partName);
1427     }
1428 }
1429 
ProcessTypeAnnotationSpecificTypes(const checker::Type * checkerType)1430 bool TSDeclGen::ProcessTypeAnnotationSpecificTypes(const checker::Type *checkerType)
1431 {
1432     if (checkerType == nullptr) {
1433         return false;
1434     }
1435 
1436     importSet_.insert(checkerType->ToString());
1437     indirectDependencyObjects_.insert(checkerType->ToString());
1438     if (HandleBasicTypes(checkerType)) {
1439         return true;
1440     }
1441     switch (checker::ETSChecker::ETSType(checkerType)) {
1442         case checker::TypeFlag::ETS_VOID:
1443         case checker::TypeFlag::ETS_NULL:
1444         case checker::TypeFlag::ETS_UNDEFINED:
1445         case checker::TypeFlag::ETS_BOOLEAN:
1446         case checker::TypeFlag::ETS_TYPE_PARAMETER:
1447         case checker::TypeFlag::ETS_NONNULLISH:
1448         case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER:
1449         case checker::TypeFlag::ETS_NEVER:
1450         case checker::TypeFlag::ETS_READONLY:
1451             OutDts(checkerType->ToString());
1452             return true;
1453         case checker::TypeFlag::ETS_ANY:
1454             OutDts("ESObject");
1455             return true;
1456         default:
1457             return false;
1458     }
1459     return false;
1460 }
1461 
ProcessTypeAnnotationType(const ir::TypeNode * typeAnnotation,const checker::Type * checkerType)1462 void TSDeclGen::ProcessTypeAnnotationType(const ir::TypeNode *typeAnnotation, const checker::Type *checkerType)
1463 {
1464     auto *aliasedType = const_cast<ir::TypeNode *>(typeAnnotation)->GetType(checker_);
1465 
1466     if (typeAnnotation->IsTSThisType()) {
1467         OutDts("this");
1468         return;
1469     }
1470     if (typeAnnotation->IsETSPrimitiveType() &&
1471         typeAnnotation->AsETSPrimitiveType()->GetPrimitiveType() == ir::PrimitiveType::VOID) {
1472         OutDts("void");
1473         return;
1474     }
1475     if (typeAnnotation->IsETSStringLiteralType() && aliasedType != nullptr) {
1476         importSet_.insert(aliasedType->ToString());
1477         OutDts(aliasedType->ToString());
1478         return;
1479     }
1480     if (typeAnnotation->IsETSTypeReference()) {
1481         ProcessETSTypeReference(typeAnnotation, checkerType);
1482         return;
1483     }
1484     if (typeAnnotation->IsETSTuple()) {
1485         ProcessETSTuple(typeAnnotation->AsETSTuple());
1486         return;
1487     }
1488     if (typeAnnotation->IsETSUnionType()) {
1489         ProcessETSUnionType(typeAnnotation->AsETSUnionType());
1490         return;
1491     }
1492     if (typeAnnotation->IsTSArrayType() && typeAnnotation->AsTSArrayType()->ElementType() != nullptr) {
1493         ProcessTSArrayType(typeAnnotation->AsTSArrayType());
1494         return;
1495     }
1496     if (typeAnnotation->IsETSFunctionType()) {
1497         ProcessETSFunctionType(typeAnnotation->AsETSFunctionType());
1498         return;
1499     }
1500     checkerType != nullptr ? GenType(checkerType) : GenType(aliasedType);
1501 }
1502 
ProcessETSTypeReference(const ir::TypeNode * typeAnnotation,const checker::Type * checkerType)1503 void TSDeclGen::ProcessETSTypeReference(const ir::TypeNode *typeAnnotation, const checker::Type *checkerType)
1504 {
1505     if (ProcessTSQualifiedName(typeAnnotation->AsETSTypeReference())) {
1506         return;
1507     }
1508     if (ProcessTypeAnnotationSpecificTypes(checkerType)) {
1509         return;
1510     }
1511     if (checkerType != nullptr && typeAnnotation->AsETSTypeReference()->Part()->GetIdent()->Name().Is("NullishType")) {
1512         OutDts(typeAnnotation->Parent()->IsTSArrayType() ? "(" : "");
1513         GenType(checkerType);
1514         OutDts(typeAnnotation->Parent()->IsTSArrayType() ? ")" : "");
1515         return;
1516     }
1517     ProcessETSTypeReferenceType(typeAnnotation->AsETSTypeReference(), checkerType);
1518 }
1519 
ProcessETSTuple(const ir::ETSTuple * etsTuple)1520 void TSDeclGen::ProcessETSTuple(const ir::ETSTuple *etsTuple)
1521 {
1522     OutDts("[");
1523     GenSeparated(
1524         etsTuple->GetTupleTypeAnnotationsList(),
1525         [this](ir::TypeNode *arg) { ProcessTypeAnnotationType(arg, arg->GetType(checker_)); }, " , ");
1526     OutDts("]");
1527 }
1528 
ProcessETSUnionType(const ir::ETSUnionType * etsUnionType)1529 void TSDeclGen::ProcessETSUnionType(const ir::ETSUnionType *etsUnionType)
1530 {
1531     state_.inUnionBodyStack.push(true);
1532     std::vector<ir::TypeNode *> filteredTypes = FilterUnionTypes(etsUnionType->Types());
1533     GenSeparated(
1534         filteredTypes, [this](ir::TypeNode *arg) { ProcessTypeAnnotationType(arg, arg->GetType(checker_)); }, " | ");
1535     state_.inUnionBodyStack.pop();
1536 }
1537 
ProcessTSArrayType(const ir::TSArrayType * tsArrayType)1538 void TSDeclGen::ProcessTSArrayType(const ir::TSArrayType *tsArrayType)
1539 {
1540     auto *elementType = tsArrayType->ElementType();
1541     auto *elementCheckerType = const_cast<ir::TypeNode *>(elementType)->GetType(checker_);
1542     if (elementCheckerType == nullptr) {
1543         return;
1544     }
1545     bool needParentheses = !elementType->IsETSTypeReference() && elementCheckerType->IsETSUnionType();
1546     OutDts(needParentheses ? "(" : "");
1547     ProcessTypeAnnotationType(elementType, elementCheckerType);
1548     OutDts(needParentheses ? ")" : "");
1549     OutDts("[]");
1550 }
1551 
ProcessETSFunctionType(const ir::ETSFunctionType * etsFunction)1552 void TSDeclGen::ProcessETSFunctionType(const ir::ETSFunctionType *etsFunction)
1553 {
1554     if (etsFunction->TypeParams() != nullptr) {
1555         GenTypeParameters(etsFunction->TypeParams());
1556     }
1557     bool inUnionBody = !state_.inUnionBodyStack.empty() && state_.inUnionBodyStack.top();
1558     OutDts(inUnionBody ? "((" : "(");
1559     GenSeparated(etsFunction->Params(), [this](ir::Expression *param) {
1560         const auto paramExpr = param->AsETSParameterExpression();
1561         const auto paramName = paramExpr->Name();
1562         const bool isRestParam = paramExpr->IsRestParameter();
1563         const bool isOptional = paramExpr->IsOptional();
1564         OutDts(isRestParam ? "..." : "", paramName.Is("=t") ? "this" : paramName, isOptional ? "?: " : ": ");
1565         ProcessTypeAnnotationType(paramExpr->TypeAnnotation(), paramExpr->TypeAnnotation()->TsType());
1566     });
1567     OutDts(") => ");
1568     ProcessTypeAnnotationType(etsFunction->ReturnType(), etsFunction->ReturnType()->TsType());
1569     OutDts(inUnionBody ? ")" : "");
1570 }
1571 
GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration * typeAlias)1572 void TSDeclGen::GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)
1573 {
1574     const auto name = typeAlias->Id()->Name().Mutf8();
1575     state_.currentTypeAliasName = name;
1576     state_.currentTypeParams = typeAlias->TypeParams();
1577     DebugPrint("GenTypeAliasDeclaration: " + name);
1578     if (!ShouldEmitDeclarationSymbol(typeAlias->Id())) {
1579         return;
1580     }
1581     if (state_.inClass) {
1582         auto indent = GetIndent();
1583         OutDts(indent);
1584         OutTs(indent);
1585     }
1586     GenAnnotations(typeAlias);
1587     if (classNode_.isIndirect || state_.inNamespace || typeAlias->IsDefaultExported()) {
1588         OutDts("type ", name);
1589     } else {
1590         OutDts("export type ", name);
1591     }
1592     GenTypeParameters(typeAlias->TypeParams());
1593     OutDts(" = ");
1594     ProcessTypeAnnotationType(typeAlias->TypeAnnotation(), typeAlias->TypeAnnotation()->GetType(checker_));
1595     OutDts(";");
1596     OutEndlDts();
1597     if (typeAlias->IsDefaultExported()) {
1598         OutDts("export default ", name, ";");
1599         OutEndlDts();
1600     }
1601 }
1602 
GenEnumDeclaration(const ir::ClassProperty * enumMember)1603 void TSDeclGen::GenEnumDeclaration(const ir::ClassProperty *enumMember)
1604 {
1605     const auto *originEnumMember = enumMember->OriginEnumMember();
1606     if (originEnumMember == nullptr) {
1607         return;
1608     }
1609 
1610     ProcessIndent();
1611 
1612     OutDts(GetKeyIdent(enumMember->Key())->Name());
1613 
1614     const auto *init = originEnumMember->Init();
1615     if (init != nullptr) {
1616         OutDts(" = ");
1617         if (!init->IsLiteral()) {
1618             LogError(diagnostic::NOT_LITERAL_ENUM_INITIALIZER, {}, init->Start());
1619         }
1620 
1621         GenLiteral(init->AsLiteral());
1622     }
1623 
1624     OutDts(",");
1625     OutEndlDts();
1626 }
1627 
GenInterfaceDeclaration(const ir::TSInterfaceDeclaration * interfaceDecl)1628 void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)
1629 {
1630     const auto interfaceName = interfaceDecl->Id()->Name().Mutf8();
1631     DebugPrint("GenInterfaceDeclaration: " + interfaceName);
1632     if (interfaceName.find("$partial") != std::string::npos) {
1633         return;
1634     }
1635     if (!ShouldEmitDeclarationSymbol(interfaceDecl->Id())) {
1636         return;
1637     }
1638     GenAnnotations(interfaceDecl);
1639     state_.inInterface = true;
1640     if (classNode_.isIndirect) {
1641         OutDts(state_.isInterfaceInNamespace ? "interface " : "declare interface ", interfaceName);
1642     } else if (!interfaceDecl->IsDefaultExported()) {
1643         OutDts(state_.isInterfaceInNamespace ? "interface " : "export declare interface ", interfaceName);
1644     } else {
1645         OutDts(state_.isInterfaceInNamespace ? "interface " : "export default interface ", interfaceName);
1646     }
1647 
1648     GenTypeParameters(interfaceDecl->TypeParams());
1649     if (!interfaceDecl->Extends().empty()) {
1650         OutDts(" extends ");
1651         GenSeparated(interfaceDecl->Extends(), [this](ir::TSInterfaceHeritage *param) {
1652             if (param->Expr()->IsETSTypeReference()) {
1653                 ProcessETSTypeReferenceType(param->Expr()->AsETSTypeReference());
1654             }
1655         });
1656     }
1657 
1658     OutDts(" {");
1659     OutEndlDts();
1660     ProcessInterfaceBody(interfaceDecl->Body());
1661     if (state_.isInterfaceInNamespace) {
1662         classNode_.indentLevel--;
1663         OutDts(GetIndent());
1664     }
1665     OutDts("}");
1666     OutEndlDts();
1667 }
1668 
ProcessInterfaceBody(const ir::TSInterfaceBody * body)1669 void TSDeclGen::ProcessInterfaceBody(const ir::TSInterfaceBody *body)
1670 {
1671     for (auto *prop : body->Body()) {
1672         if (prop->IsMethodDefinition()) {
1673             ProcessInterfaceMethodDefinition(prop->AsMethodDefinition());
1674         }
1675     }
1676 }
1677 
ProcessInterfaceMethodDefinition(const ir::MethodDefinition * methodDef)1678 void TSDeclGen::ProcessInterfaceMethodDefinition(const ir::MethodDefinition *methodDef)
1679 {
1680     if (GenInterfaceProp(methodDef)) {
1681         return;
1682     }
1683 
1684     if (methodDef->IsGetter() || methodDef->IsSetter()) {
1685         GenMethodDeclaration(methodDef);
1686     }
1687     if (!methodDef->Overloads().empty()) {
1688         for (const auto *overloadMethd : methodDef->Overloads()) {
1689             if (overloadMethd->IsGetter() || overloadMethd->IsSetter()) {
1690                 GenMethodDeclaration(overloadMethd);
1691             }
1692         }
1693         return;
1694     }
1695     if (!methodDef->IsGetter() && !methodDef->IsSetter()) {
1696         GenMethodDeclaration(methodDef);
1697     }
1698 }
1699 
GenInterfaceProp(const ir::MethodDefinition * methodDef)1700 bool TSDeclGen::GenInterfaceProp(const ir::MethodDefinition *methodDef)
1701 {
1702     if (!methodDef->IsGetter()) {
1703         return false;
1704     }
1705     if (methodDef->OriginalNode() == nullptr) {
1706         return false;
1707     }
1708     if (!methodDef->OriginalNode()->IsClassProperty()) {
1709         return false;
1710     }
1711 
1712     const auto methodName = GetKeyIdent(methodDef->Key())->Name().Mutf8();
1713     const auto classProp = methodDef->OriginalNode()->AsClassProperty();
1714     bool isReadOnly = classProp->IsReadonly();
1715     bool isOptional = classProp->IsOptionalDeclaration();
1716     ProcessIndent();
1717     if (isReadOnly) {
1718         OutDts("readonly ");
1719     }
1720     OutDts(methodName);
1721     if (isOptional) {
1722         OutDts("?");
1723     }
1724     OutDts(": ");
1725     if (methodDef->TsType()->IsETSFunctionType()) {
1726         const auto *sig = GetFuncSignature(methodDef->TsType()->AsETSFunctionType(), methodDef);
1727         ProcessFunctionReturnType(sig);
1728         OutDts(";");
1729         OutEndlDts();
1730         return true;
1731     }
1732     ES2PANDA_ASSERT(methodDef->Function() != nullptr);
1733     GenType(methodDef->Function()->Signature()->ReturnType());
1734     OutDts(";");
1735     OutEndlDts();
1736     return true;
1737 }
1738 
ProcessMethodDefinition(const ir::MethodDefinition * methodDef,std::unordered_set<std::string> & processedMethods)1739 void TSDeclGen::ProcessMethodDefinition(const ir::MethodDefinition *methodDef,
1740                                         std::unordered_set<std::string> &processedMethods)
1741 {
1742     const auto methodName = GetKeyIdent(methodDef->Key())->Name().Mutf8();
1743     if (processedMethods.find(methodName) != processedMethods.end()) {
1744         return;
1745     }
1746     if (methodDef->IsGetter() || methodDef->IsSetter()) {
1747         GenMethodDeclaration(methodDef);
1748         processedMethods.insert(methodName);
1749     }
1750     if (!methodDef->Overloads().empty()) {
1751         for (const auto *overloadMethd : methodDef->Overloads()) {
1752             if (overloadMethd->IsGetter() || overloadMethd->IsSetter()) {
1753                 GenMethodDeclaration(overloadMethd);
1754             }
1755         }
1756         return;
1757     }
1758     if (!methodDef->IsGetter() && !methodDef->IsSetter()) {
1759         GenMethodDeclaration(methodDef);
1760         processedMethods.insert(methodName);
1761     }
1762 }
1763 
PrepareClassDeclaration(const ir::ClassDefinition * classDef)1764 void TSDeclGen::PrepareClassDeclaration(const ir::ClassDefinition *classDef)
1765 {
1766     std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";";
1767     std::replace(classDescriptor.begin(), classDescriptor.end(), '.', '/');
1768     state_.currentClassDescriptor = classDescriptor;
1769     state_.inGlobalClass = classDef->IsGlobal();
1770     if (classDef->IsNamespaceTransformed()) {
1771         state_.inNamespace = true;
1772         state_.isClassInNamespace = false;
1773         state_.isDeclareNamespace = classDef->IsDeclare();
1774     } else {
1775         state_.isClassInNamespace = true;
1776     }
1777     classNode_.isStruct = classDef->IsFromStruct();
1778     classNode_.isIndirect = false;
1779 }
1780 
ShouldSkipClassDeclaration(const std::string_view & className) const1781 bool TSDeclGen::ShouldSkipClassDeclaration(const std::string_view &className) const
1782 {
1783     return className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS ||
1784            className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos);
1785 }
1786 
EmitDeclarationPrefix(const ir::ClassDefinition * classDef,const std::string & typeName,const std::string_view & className)1787 void TSDeclGen::EmitDeclarationPrefix(const ir::ClassDefinition *classDef, const std::string &typeName,
1788                                       const std::string_view &className)
1789 {
1790     if (classDef->IsDefaultExported()) {
1791         OutDts(classNode_.indentLevel > 1 ? typeName : "declare " + typeName, className);
1792     } else if (classDef->IsExported() || declgenOptions_.exportAll) {
1793         OutDts(classNode_.indentLevel > 1 ? typeName : "export declare " + typeName, className);
1794     } else {
1795         OutDts(classNode_.indentLevel > 1 ? typeName : "declare " + typeName, className);
1796     }
1797 }
1798 
EmitClassDeclaration(const ir::ClassDefinition * classDef,const std::string_view & className)1799 void TSDeclGen::EmitClassDeclaration(const ir::ClassDefinition *classDef, const std::string_view &className)
1800 {
1801     if (classDef->IsNamespaceTransformed()) {
1802         EmitDeclarationPrefix(classDef, "namespace ", className);
1803         OutTs("export namespace ", className, " {");
1804         OutEndlTs();
1805     } else if (classDef->IsEnumTransformed()) {
1806         EmitDeclarationPrefix(classDef, "enum ", className);
1807     } else if (classDef->IsFromStruct()) {
1808         EmitDeclarationPrefix(classDef, "struct ", className);
1809     } else if (classDef->IsAbstract()) {
1810         EmitDeclarationPrefix(classDef, "abstract class ", className);
1811     } else {
1812         EmitDeclarationPrefix(classDef, "class ", className);
1813     }
1814 }
1815 
GetIndent() const1816 std::string TSDeclGen::GetIndent() const
1817 {
1818     return std::string(classNode_.indentLevel * INDENT.size(), ' ');
1819 }
1820 
GenPartName(std::string & partName)1821 void TSDeclGen::GenPartName(std::string &partName)
1822 {
1823     if (partName == "Boolean") {
1824         partName = "boolean";
1825     } else if (stringTypes_.count(partName) != 0U) {
1826         partName = "string";
1827     } else if (numberTypes_.count(partName) != 0U) {
1828         partName = "number";
1829     } else if (partName == "ESValue") {
1830         partName = "ESObject";
1831     } else if (partName == "BigInt") {
1832         partName = "bigint";
1833     } else if (partName == "Exception" || partName == "NullPointerError") {
1834         partName = "Error";
1835     } else if (partName == "Any") {
1836         partName = "ESObject";
1837     } else if (partName == "Floating" || partName == "Integral") {
1838         partName = "number";
1839     }
1840 }
1841 
ProcessIndent()1842 void TSDeclGen::ProcessIndent()
1843 {
1844     if (state_.isInterfaceInNamespace || state_.inEnum) {
1845         OutDts(GetIndent());
1846     } else if (classNode_.hasNestedClass || state_.inNamespace) {
1847         auto indent = GetIndent();
1848         OutDts(indent);
1849         OutTs(indent);
1850     } else {
1851         OutDts(INDENT);
1852     }
1853 }
1854 
HandleClassDeclarationTypeInfo(const ir::ClassDefinition * classDef,const std::string_view & className)1855 void TSDeclGen::HandleClassDeclarationTypeInfo(const ir::ClassDefinition *classDef, const std::string_view &className)
1856 {
1857     if (classNode_.hasNestedClass) {
1858         classNode_.indentLevel--;
1859         ES2PANDA_ASSERT(classNode_.indentLevel != static_cast<decltype(classNode_.indentLevel)>(-1));
1860     }
1861     GenAnnotations(classDef);
1862     if (classNode_.hasNestedClass) {
1863         OutDts(GetIndent());
1864         classNode_.indentLevel++;
1865     }
1866     EmitClassDeclaration(classDef, className);
1867     GenTypeParameters(classDef->TypeParams());
1868 
1869     const auto *super = classDef->Super();
1870     state_.super = super;
1871     if (super != nullptr && !classDef->IsEnumTransformed()) {
1872         OutDts(" extends ");
1873         HandleClassInherit(super);
1874     }
1875 
1876     if (!classDef->Implements().empty()) {
1877         OutDts(" implements ");
1878         GenSeparated(classDef->Implements(), [this](ir::TSClassImplements *impl) { HandleClassInherit(impl->Expr()); });
1879     } else if (classDef->TsType() != nullptr && classDef->TsType()->IsETSObjectType() &&
1880                !classDef->TsType()->AsETSObjectType()->Interfaces().empty()) {
1881         OutDts(" implements ");
1882         const auto &interfaces = classDef->TsType()->AsETSObjectType()->Interfaces();
1883         GenSeparated(interfaces, [this](checker::ETSObjectType *interface) { GenType(interface); });
1884     }
1885 
1886     OutDts(" {");
1887     OutEndlDts();
1888 }
1889 
HandleClassInherit(const ir::Expression * expr)1890 void TSDeclGen::HandleClassInherit(const ir::Expression *expr)
1891 {
1892     if (expr->IsETSTypeReference()) {
1893         ProcessETSTypeReferenceType(expr->AsETSTypeReference());
1894     } else if (!expr->TsType()->IsTypeError()) {
1895         GenType(expr->TsType());
1896     }
1897 }
1898 
EmitClassGlueCode(const ir::ClassDefinition * classDef,const std::string & className)1899 void TSDeclGen::EmitClassGlueCode(const ir::ClassDefinition *classDef, const std::string &className)
1900 {
1901     if (classNode_.isIndirect || classDef->IsExportedType()) {
1902         return;
1903     }
1904     const std::string exportPrefix = classDef->Parent()->IsDefaultExported() ? "const " : "export const ";
1905     OutTs(exportPrefix, className, " = (globalThis as any).Panda.getClass('", state_.currentClassDescriptor, "');");
1906     OutEndlTs();
1907 
1908     if (classDef->Parent()->IsDefaultExported()) {
1909         OutTs("export default ", className, ";");
1910         OutEndlTs();
1911     }
1912 }
1913 
ProcessMethodsFromInterfaces(std::unordered_set<std::string> & processedMethods,const ArenaVector<checker::ETSObjectType * > & interfaces)1914 void TSDeclGen::ProcessMethodsFromInterfaces(std::unordered_set<std::string> &processedMethods,
1915                                              const ArenaVector<checker::ETSObjectType *> &interfaces)
1916 {
1917     if (interfaces.empty()) {
1918         return;
1919     }
1920     for (const auto &interface : interfaces) {
1921         auto methods = interface->Methods();
1922         std::unordered_set<std::string> processedInterfaceMethods;
1923         for (const auto &method : methods) {
1924             if ((method->Flags() & (varbinder::VariableFlags::PUBLIC)) != 0U &&
1925                 (method->Flags() & (varbinder::VariableFlags::STATIC)) == 0U &&
1926                 processedMethods.find(method->Name().Mutf8()) == processedMethods.end()) {
1927                 ProcessMethodDefinition(
1928                     method->AsLocalVariable()->Declaration()->AsFunctionDecl()->Node()->AsMethodDefinition(),
1929                     processedInterfaceMethods);
1930             }
1931         }
1932         ProcessMethodsFromInterfaces(processedMethods, interface->Interfaces());
1933     }
1934 }
1935 
ProcessClassBody(const ir::ClassDefinition * classDef)1936 void TSDeclGen::ProcessClassBody(const ir::ClassDefinition *classDef)
1937 {
1938     state_.inClass = true;
1939     std::unordered_set<std::string> processedMethods;
1940     for (const auto *prop : classDef->Body()) {
1941         if (classDef->IsEnumTransformed()) {
1942             if (prop->IsClassProperty()) {
1943                 state_.inEnum = true;
1944                 GenPropDeclaration(prop->AsClassProperty());
1945             }
1946         } else if (prop->IsTSInterfaceDeclaration()) {
1947             state_.isInterfaceInNamespace = true;
1948             OutDts(GetIndent());
1949             classNode_.indentLevel++;
1950             GenInterfaceDeclaration(prop->AsTSInterfaceDeclaration());
1951             state_.inInterface = false;
1952             state_.isInterfaceInNamespace = false;
1953         } else if (prop->IsTSTypeAliasDeclaration()) {
1954             GenTypeAliasDeclaration(prop->AsTSTypeAliasDeclaration());
1955         } else if (prop->IsMethodDefinition()) {
1956             ProcessMethodDefinition(prop->AsMethodDefinition(), processedMethods);
1957         } else if (prop->IsClassProperty()) {
1958             const auto classProp = prop->AsClassProperty();
1959             const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
1960             if (propName.find("<property>") != std::string::npos) {
1961                 continue;
1962             }
1963             GenPropDeclaration(classProp);
1964         } else if (prop->IsClassDeclaration() && classDef->IsNamespaceTransformed()) {
1965             classNode_.hasNestedClass = true;
1966             OutTs(GetIndent());
1967             classNode_.indentLevel++;
1968             GenClassDeclaration(prop->AsClassDeclaration());
1969             state_.isClassInNamespace = false;
1970         } else if (prop->IsClassDeclaration() && classDef->IsFromStruct()) {
1971             GenClassDeclaration(prop->AsClassDeclaration());
1972         }
1973     }
1974     if (classDef->TsType() != nullptr && classDef->TsType()->IsETSObjectType()) {
1975         ProcessMethodsFromInterfaces(processedMethods, classDef->TsType()->AsETSObjectType()->Interfaces());
1976     }
1977 }
1978 
CloseClassBlock(const bool isDts)1979 void TSDeclGen::CloseClassBlock(const bool isDts)
1980 {
1981     auto indent = GetIndent();
1982     if (isDts) {
1983         OutDts(indent, "}");
1984         OutEndlDts();
1985     } else {
1986         OutTs(indent, "}");
1987         OutEndlTs();
1988     }
1989 }
1990 
GenClassDeclaration(const ir::ClassDeclaration * classDecl)1991 void TSDeclGen::GenClassDeclaration(const ir::ClassDeclaration *classDecl)
1992 {
1993     const auto *classDef = classDecl->Definition();
1994     PrepareClassDeclaration(classDef);
1995     const auto className = classDef->Ident()->Name().Mutf8();
1996     DebugPrint("GenClassDeclaration: " + className);
1997     if (ShouldSkipClassDeclaration(className)) {
1998         return;
1999     }
2000     if (state_.inGlobalClass) {
2001         classNode_.indentLevel = 1;
2002         ProcessClassBody(classDef);
2003     }
2004     if (!state_.inGlobalClass && ShouldEmitDeclarationSymbol(classDef->Ident())) {
2005         HandleClassDeclarationTypeInfo(classDef, className);
2006         if (!classDef->IsNamespaceTransformed()) {
2007             EmitClassGlueCode(classDef, className);
2008         }
2009         ProcessClassBody(classDef);
2010         std::size_t originalIndentLevel = classNode_.indentLevel;
2011         classNode_.indentLevel > 0 ? classNode_.indentLevel-- : classNode_.indentLevel = 0;
2012         CloseClassBlock(true);
2013         classNode_.indentLevel = originalIndentLevel;
2014     }
2015     if (classNode_.hasNestedClass || state_.inNamespace || state_.inEnum) {
2016         classNode_.indentLevel > 1 ? classNode_.indentLevel-- : classNode_.indentLevel = 1;
2017         if (!ShouldEmitDeclarationSymbol(classDef->Ident())) {
2018             return;
2019         }
2020         ES2PANDA_ASSERT(classNode_.indentLevel != static_cast<decltype(classNode_.indentLevel)>(-1));
2021         if (!state_.isClassInNamespace) {
2022             CloseClassBlock(false);
2023         }
2024         if (state_.inEnum) {
2025             state_.inEnum = false;
2026         }
2027     }
2028     if (classDef->IsDefaultExported()) {
2029         OutDts("export default ", className, ";");
2030         OutEndlDts();
2031     }
2032 }
2033 
ShouldSkipMethodDeclaration(const ir::MethodDefinition * methodDef)2034 bool TSDeclGen::ShouldSkipMethodDeclaration(const ir::MethodDefinition *methodDef)
2035 {
2036     const auto methodIdent = GetKeyIdent(methodDef->Key());
2037     const auto methodName = methodIdent->Name().Mutf8();
2038     if (methodName.find('#') != std::string::npos || methodName.find("$asyncimpl") != std::string::npos ||
2039         (!state_.inGlobalClass && (methodName == compiler::Signatures::INIT_METHOD ||
2040                                    methodName == compiler::Signatures::INITIALIZER_BLOCK_INIT))) {
2041         return true;
2042     }
2043     if (methodDef->IsPrivate() && !methodDef->IsConstructor()) {
2044         return true;
2045     }
2046     if (methodName == compiler::Signatures::INIT_METHOD) {
2047         return true;
2048     }
2049     if (classNode_.isStruct && methodDef->IsConstructor()) {
2050         return true;
2051     }
2052     return false;
2053 }
2054 
EmitMethodGlueCode(const std::string & methodName,const ir::Identifier * methodIdentifier)2055 void TSDeclGen::EmitMethodGlueCode(const std::string &methodName, const ir::Identifier *methodIdentifier)
2056 {
2057     if (!ShouldEmitDeclarationSymbol(methodIdentifier)) {
2058         return;
2059     }
2060     if (state_.inNamespace) {
2061         OutTs("export const ", methodName,
2062               " = (globalThis as any).Panda.getClass('" + state_.currentClassDescriptor + "')." + methodName + ";");
2063         OutEndlTs();
2064         return;
2065     }
2066     if (methodIdentifier->Parent()->IsDefaultExported()) {
2067         OutTs("const ", methodName, " = (globalThis as any).Panda.getFunction('", state_.currentClassDescriptor, "', '",
2068               methodName, "');");
2069         OutEndlTs();
2070         OutTs("export default ", methodName, ";");
2071         OutEndlTs();
2072     } else {
2073         OutTs("export const ", methodName, " = (globalThis as any).Panda.getFunction('", state_.currentClassDescriptor,
2074               "', '", methodName, "');");
2075         OutEndlTs();
2076     }
2077 }
2078 
GenMethodDeclaration(const ir::MethodDefinition * methodDef)2079 void TSDeclGen::GenMethodDeclaration(const ir::MethodDefinition *methodDef)
2080 {
2081     if (ShouldSkipMethodDeclaration(methodDef)) {
2082         return;
2083     }
2084     const auto methodIdent = GetKeyIdent(methodDef->Key());
2085     const auto methodName = methodIdent->Name().Mutf8();
2086     if (GenMethodDeclarationPrefix(methodDef, methodIdent, methodName)) {
2087         return;
2088     }
2089     GenMethodSignature(methodDef, methodIdent, methodName);
2090 
2091     OutDts(";");
2092     OutEndlDts();
2093 
2094     if (methodDef->IsDefaultExported()) {
2095         OutDts("export default ", methodName, ";");
2096         OutEndlDts();
2097     }
2098 }
2099 
GenMethodDeclarationPrefix(const ir::MethodDefinition * methodDef,const ir::Identifier * methodIdent,const std::string & methodName)2100 bool TSDeclGen::GenMethodDeclarationPrefix(const ir::MethodDefinition *methodDef, const ir::Identifier *methodIdent,
2101                                            const std::string &methodName)
2102 {
2103     if (state_.inGlobalClass) {
2104         if (!ShouldEmitDeclarationSymbol(methodIdent)) {
2105             return true;
2106         }
2107         if (methodDef->IsDefaultExported()) {
2108             OutDts("declare function ");
2109         } else {
2110             OutDts("export declare function ");
2111         }
2112     } else {
2113         if (state_.inNamespace && !state_.isClassInNamespace && !state_.isInterfaceInNamespace &&
2114             !ShouldEmitDeclarationSymbol(methodIdent) && !methodDef->IsConstructor()) {
2115             return true;
2116         }
2117         auto methDefFunc = methodDef->Function();
2118         if (methDefFunc != nullptr && !methDefFunc->Annotations().empty()) {
2119             GenAnnotations(methDefFunc);
2120         }
2121         ProcessIndent();
2122         GenModifier(methodDef);
2123     }
2124     EmitMethodGlueCode(methodName, methodIdent);
2125 
2126     ES2PANDA_ASSERT(methodDef->Function() != nullptr);
2127     if (methodDef->Function()->IsAbstract() && !state_.inInterface &&
2128         !(methodDef->Parent()->IsTSInterfaceBody() ||
2129           (methodDef->BaseOverloadMethod() != nullptr &&
2130            methodDef->BaseOverloadMethod()->Parent()->IsTSInterfaceBody()))) {
2131         OutDts("abstract ");
2132     }
2133     if (methodDef->IsGetter()) {
2134         OutDts("get ");
2135     }
2136     if (methodDef->IsSetter()) {
2137         OutDts("set ");
2138     }
2139     return false;
2140 }
2141 
GenMethodSignature(const ir::MethodDefinition * methodDef,const ir::Identifier * methodIdent,const std::string & methodName)2142 void TSDeclGen::GenMethodSignature(const ir::MethodDefinition *methodDef, const ir::Identifier *methodIdent,
2143                                    const std::string &methodName)
2144 {
2145     if (methodDef->IsSetter()) {
2146         OutDts(methodName, "(value: ");
2147         const auto *sig = methodDef->TsType()->AsETSFunctionType()->CallSignatures()[0];
2148         if (sig->HasFunction()) {
2149             ProcessFunctionReturnType(sig);
2150         } else {
2151             GenType(sig->Params()[0]->TsType());
2152         }
2153         OutDts(")");
2154     } else {
2155         DebugPrint("  GenMethodDeclaration: " + methodName);
2156         OutDts(methodName);
2157 
2158         if (methodDef->TsType() == nullptr) {
2159             LogWarning(diagnostic::UNTYPED_METHOD, {methodName}, methodIdent->Start());
2160             OutDts(": ESObject");
2161             return;
2162         }
2163         if (methodDef->TsType()->IsETSFunctionType()) {
2164             GenFunctionType(methodDef->TsType()->AsETSFunctionType(), methodDef);
2165         }
2166     }
2167 }
2168 
EmitPropGlueCode(const ir::ClassProperty * classProp,const std::string & propName)2169 void TSDeclGen::EmitPropGlueCode(const ir::ClassProperty *classProp, const std::string &propName)
2170 {
2171     std::string propAccess;
2172     if (state_.inGlobalClass) {
2173         propAccess = " = (globalThis as any).Panda.getClass('" + globalDesc_ + "')." + propName + ";";
2174     } else {
2175         propAccess = " = (globalThis as any).Panda.getClass('" + state_.currentClassDescriptor + "')." + propName + ";";
2176     }
2177     const bool isConst = classProp->IsConst();
2178     const bool isDefaultExported = classProp->IsDefaultExported();
2179     if (isDefaultExported) {
2180         OutTs(isConst ? "const " : "let ", propName, propAccess);
2181         OutEndlTs();
2182         OutTs("export default ", propName, ";");
2183     } else {
2184         OutTs(isConst ? "export const " : "export let ", propName, propAccess);
2185     }
2186     OutEndlTs();
2187 }
2188 
ProcessClassPropertyType(const ir::ClassProperty * classProp)2189 void TSDeclGen::ProcessClassPropertyType(const ir::ClassProperty *classProp)
2190 {
2191     auto value = classProp->AsClassProperty()->Value();
2192     if (value != nullptr && value->IsETSNewClassInstanceExpression() &&
2193         value->AsETSNewClassInstanceExpression()->GetTypeRef() != nullptr &&
2194         value->AsETSNewClassInstanceExpression()->GetTypeRef()->IsETSTypeReference()) {
2195         auto typeReference = classProp->Value()->AsETSNewClassInstanceExpression()->GetTypeRef()->AsETSTypeReference();
2196         ProcessETSTypeReferenceType(typeReference);
2197         return;
2198     }
2199     if (classProp->TypeAnnotation() != nullptr) {
2200         ProcessTypeAnnotationType(classProp->TypeAnnotation(), classProp->TsType());
2201         return;
2202     }
2203     if (value != nullptr && value->IsArrowFunctionExpression() &&
2204         value->AsArrowFunctionExpression()->Function() != nullptr &&
2205         value->AsArrowFunctionExpression()->Function()->TypeParams() != nullptr) {
2206         GenTypeParameters(value->AsArrowFunctionExpression()->Function()->TypeParams());
2207     }
2208     GenType(classProp->TsType());
2209 }
2210 
GenPropDeclaration(const ir::ClassProperty * classProp)2211 void TSDeclGen::GenPropDeclaration(const ir::ClassProperty *classProp)
2212 {
2213     if (state_.inGlobalClass) {
2214         GenGlobalVarDeclaration(classProp);
2215         return;
2216     }
2217     if (classProp->IsPrivate()) {
2218         return;
2219     }
2220 
2221     const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
2222     // The class property generated for enums starts with "#" are invalid properties, and should not be generated.
2223     if (propName.find('#') != std::string::npos) {
2224         DebugPrint("  Skip Generate enum PropDeclaration: " + propName);
2225         return;
2226     }
2227 
2228     if (state_.inEnum) {
2229         GenEnumDeclaration(classProp);
2230         return;
2231     }
2232 
2233     DebugPrint("  GenPropDeclaration: " + propName);
2234 
2235     ProcessClassPropDeclaration(classProp);
2236 
2237     if (classNode_.hasNestedClass || state_.inNamespace) {
2238         EmitPropGlueCode(classProp, propName);
2239     }
2240 }
2241 
ProcessClassPropDeclaration(const ir::ClassProperty * classProp)2242 void TSDeclGen::ProcessClassPropDeclaration(const ir::ClassProperty *classProp)
2243 {
2244     if (!state_.inInterface && (!state_.inNamespace || state_.isClassInNamespace) && !classNode_.isStruct) {
2245         GenPropAccessor(classProp, "get ");
2246         if (!classProp->IsReadonly()) {
2247             GenPropAccessor(classProp, "set ");
2248         }
2249     } else {
2250         if (!classProp->Annotations().empty()) {
2251             GenAnnotations(classProp);
2252         }
2253         ProcessIndent();
2254         if (!classNode_.isStruct) {
2255             GenModifier(classProp, true);
2256         }
2257         const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
2258         OutDts(propName);
2259         OutDts(": ");
2260         if (!state_.inNamespace) {
2261             classProp->IsStatic() ? OutDts("ESObject") : GenType(classProp->TsType());
2262         } else {
2263             ProcessClassPropertyType(classProp);
2264         }
2265         OutDts(";");
2266         OutEndlDts();
2267     }
2268 }
2269 
GenPropAccessor(const ir::ClassProperty * classProp,const std::string & accessorKind)2270 void TSDeclGen::GenPropAccessor(const ir::ClassProperty *classProp, const std::string &accessorKind)
2271 {
2272     if (accessorKind != "set " && accessorKind != "get ") {
2273         return;
2274     }
2275     if (!classProp->Annotations().empty()) {
2276         GenAnnotations(classProp);
2277     }
2278     ProcessIndent();
2279     GenModifier(classProp);
2280 
2281     const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
2282     OutDts(accessorKind, propName, accessorKind == "set " ? "(value: " : "(): ");
2283     if (classProp->TypeAnnotation() != nullptr) {
2284         ProcessTypeAnnotationType(classProp->TypeAnnotation(), classProp->TsType());
2285     } else {
2286         GenType(classProp->TsType());
2287     }
2288     OutDts(accessorKind == "set " ? ");" : ";");
2289     OutEndlDts();
2290 }
2291 
GenGlobalVarDeclaration(const ir::ClassProperty * globalVar)2292 void TSDeclGen::GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)
2293 {
2294     if (!globalVar->IsExported() && !globalVar->IsDefaultExported() && !declgenOptions_.exportAll) {
2295         return;
2296     }
2297 
2298     const auto symbol = GetKeyIdent(globalVar->Key());
2299     auto varName = symbol->Name().Mutf8();
2300     const std::string prefix = "gensym%%_";
2301     if (varName.rfind(prefix, 0) == 0) {
2302         varName = varName.substr(prefix.size());
2303     }
2304     const bool isConst = globalVar->IsConst();
2305     const bool isDefaultExported = globalVar->IsDefaultExported();
2306     DebugPrint("GenGlobalVarDeclaration: " + varName);
2307 
2308     GenAnnotations(globalVar);
2309 
2310     if (isDefaultExported) {
2311         OutDts(isConst ? "declare const " : "declare let ", varName, ": ");
2312     } else {
2313         OutDts(isConst ? "export declare const " : "export declare let ", varName, ": ");
2314     }
2315     ProcessClassPropertyType(globalVar);
2316     OutDts(";");
2317     OutEndlDts();
2318     if (isDefaultExported) {
2319         OutDts("export default ", varName, ";");
2320         OutEndlDts();
2321     }
2322 
2323     EmitPropGlueCode(globalVar, varName);
2324 }
2325 
WriteToFile(const std::string & path,const std::string & content,checker::ETSChecker * checker)2326 bool WriteToFile(const std::string &path, const std::string &content, checker::ETSChecker *checker)
2327 {
2328     std::ofstream outStream(path);  // ark::os::GetAbsolutePath(*pathValue)
2329     if (outStream.fail()) {
2330         checker->DiagnosticEngine().LogDiagnostic(diagnostic::OPEN_FAILED, util::DiagnosticMessageParams {path});
2331         return false;
2332     }
2333     outStream << content;
2334     outStream.close();
2335     return true;
2336 }
2337 
GenerateTsDeclarations(checker::ETSChecker * checker,const ark::es2panda::parser::Program * program,const DeclgenOptions & declgenOptions)2338 bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program,
2339                             const DeclgenOptions &declgenOptions)
2340 {
2341     TSDeclGen declBuilder(checker, program);
2342     declBuilder.SetDeclgenOptions(declgenOptions);
2343 
2344     if ((declBuilder.GetDeclgenOptions().outputDeclEts.empty() && !declBuilder.GetDeclgenOptions().outputEts.empty()) ||
2345         (!declBuilder.GetDeclgenOptions().outputDeclEts.empty() && declBuilder.GetDeclgenOptions().outputEts.empty())) {
2346         checker->DiagnosticEngine().LogDiagnostic(diagnostic::GENERATE_DYNAMIC_DECLARATIONS,
2347                                                   util::DiagnosticMessageParams {});
2348         return false;
2349     }
2350     if (declBuilder.GetDeclgenOptions().outputDeclEts.empty() && declBuilder.GetDeclgenOptions().outputEts.empty()) {
2351         checker->DiagnosticEngine().LogDiagnostic(diagnostic::MISSING_OUTPUT_FILE, util::DiagnosticMessageParams {""});
2352         return false;
2353     }
2354 
2355     if (!declBuilder.Generate()) {
2356         return false;
2357     }
2358 
2359     std::string outputEts = declBuilder.GetTsOutput();
2360     std::string outputDEts = declBuilder.GetDtsOutput();
2361 
2362     declBuilder.ResetTsOutput();
2363     declBuilder.ResetDtsOutput();
2364 
2365     declBuilder.GenImportDeclarations();
2366 
2367     std::string importOutputEts = declBuilder.GetTsOutput();
2368     std::string importOutputDEts = declBuilder.GetDtsOutput();
2369 
2370     std::string combineEts = importOutputEts + outputEts;
2371     std::string combinedDEts = importOutputDEts + outputDEts;
2372 
2373     if (!declBuilder.GetDeclgenOptions().recordFile.empty()) {
2374         declBuilder.ResetDtsOutput();
2375         declBuilder.GenImportRecordDeclarations(declBuilder.GetDeclgenOptions().recordFile);
2376         std::string recordImportOutputDEts = declBuilder.GetDtsOutput();
2377         combinedDEts = recordImportOutputDEts + combinedDEts;
2378     }
2379 
2380     return WriteOutputFiles(declBuilder.GetDeclgenOptions(), combineEts, combinedDEts, checker);
2381 }
2382 
ValidateDeclgenOptions(const DeclgenOptions & options,checker::ETSChecker * checker)2383 bool ValidateDeclgenOptions(const DeclgenOptions &options, checker::ETSChecker *checker)
2384 {
2385     if ((options.outputDeclEts.empty() && !options.outputEts.empty()) ||
2386         (!options.outputDeclEts.empty() && options.outputEts.empty())) {
2387         checker->DiagnosticEngine().LogDiagnostic(diagnostic::GENERATE_DYNAMIC_DECLARATIONS,
2388                                                   util::DiagnosticMessageParams {});
2389         return false;
2390     }
2391     if (options.outputDeclEts.empty() && options.outputEts.empty()) {
2392         checker->DiagnosticEngine().LogDiagnostic(diagnostic::MISSING_OUTPUT_FILE, util::DiagnosticMessageParams {""});
2393         return false;
2394     }
2395     return true;
2396 }
2397 
WriteOutputFiles(const DeclgenOptions & options,const std::string & combinedEts,const std::string & combinedDEts,checker::ETSChecker * checker)2398 bool WriteOutputFiles(const DeclgenOptions &options, const std::string &combinedEts, const std::string &combinedDEts,
2399                       checker::ETSChecker *checker)
2400 {
2401     if (!options.outputDeclEts.empty()) {
2402         if (!WriteToFile(options.outputDeclEts, combinedDEts, checker)) {
2403             return false;
2404         }
2405     }
2406 
2407     if (!options.outputEts.empty()) {
2408         if (!WriteToFile(options.outputEts, combinedEts, checker)) {
2409             return false;
2410         }
2411     }
2412     return true;
2413 }
2414 }  // namespace ark::es2panda::declgen_ets2ts
2415