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 ¶ms = {},
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 ¶ms = {},
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