1/**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "declgenEts2Ts.h"
17
18#include "ir/base/classProperty.h"
19#include "ir/base/methodDefinition.h"
20#include "ir/base/scriptFunction.h"
21#include "ir/ets/etsImportDeclaration.h"
22#include "ir/expressions/identifier.h"
23#include "ir/expressions/literals/numberLiteral.h"
24#include "ir/module/importSpecifier.h"
25#include "ir/statements/blockStatement.h"
26#include "ir/statements/classDeclaration.h"
27#include "ir/ts/tsEnumMember.h"
28#include "ir/ts/tsInterfaceBody.h"
29#include "ir/ts/tsTypeAliasDeclaration.h"
30#include "ir/ts/tsTypeParameter.h"
31
32#define DEBUG_PRINT 0
33
34namespace ark::es2panda::declgen_ets2ts {
35
36static void DebugPrint([[maybe_unused]] const std::string &msg)
37{
38#if DEBUG_PRINT
39    std::cerr << msg << std::endl;
40#endif
41}
42
43static void Warning(const std::string &msg)
44{
45    std::cerr << "Warning declgen ets2ts: " << msg << std::endl;
46}
47
48void TSDeclGen::Generate()
49{
50    std::stringstream license;
51    license << "/*\n";
52    license << " * Copyright (c) 2023-2024 Huawei Device Co., Ltd.\n";
53    license << " * Licensed under the Apache License, Version 2.0 (the \"License\");\n";
54    license << " * you may not use this file except in compliance with the License.\n";
55    license << " * You may obtain a copy of the License at\n";
56    license << " *\n";
57    license << " *     http://www.apache.org/licenses/LICENSE-2.0\n";
58    license << " *\n";
59    license << " * Unless required by applicable law or agreed to in writing, software\n";
60    license << " * distributed under the License is distributed on an \"AS IS\" BASIS,\n";
61    license << " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n";
62    license << " * See the License for the specific language governing permissions and\n";
63    license << " * limitations under the License.\n";
64    license << " */\n\n";
65    Out(license.str());
66    Out("declare const exports: any;");
67    OutEndl();
68    Out("let ETSGLOBAL: any = (globalThis as any).Panda.getClass('LETSGLOBAL;');");
69    OutEndl(2U);
70
71    for (auto *globalStatement : program_->Ast()->Statements()) {
72        ResetState();
73        if (globalStatement->IsETSImportDeclaration()) {
74            GenImportDeclaration(globalStatement->AsETSImportDeclaration());
75        } else if (globalStatement->IsTSEnumDeclaration()) {
76            GenEnumDeclaration(globalStatement->AsTSEnumDeclaration());
77        } else if (globalStatement->IsClassDeclaration()) {
78            // The classes generated for enums starts with '#' but those are invalid names and
79            // not requred for the ts code
80            if (globalStatement->AsClassDeclaration()->Definition()->Ident()->Name().Mutf8().find('#') ==
81                std::string::npos) {
82                GenClassDeclaration(globalStatement->AsClassDeclaration());
83            }
84        } else if (globalStatement->IsTSInterfaceDeclaration()) {
85            GenInterfaceDeclaration(globalStatement->AsTSInterfaceDeclaration());
86        } else if (globalStatement->IsTSTypeAliasDeclaration()) {
87            GenTypeAliasDeclaration(globalStatement->AsTSTypeAliasDeclaration());
88        }
89    }
90}
91
92template <class T, class CB>
93void TSDeclGen::GenSeparated(const T &container, const CB &cb, const char *separator)
94{
95    if (container.empty()) {
96        return;
97    }
98
99    cb(container[0]);
100    for (std::size_t i = 1; i < container.size(); ++i) {
101        Out(separator);
102        cb(container[i]);
103    }
104}
105
106void TSDeclGen::ThrowError(const std::string_view message, const lexer::SourcePosition &pos = lexer::SourcePosition())
107{
108    lexer::LineIndex index(program_->SourceCode());
109    const lexer::SourceLocation loc = index.GetLocation(pos);
110
111    throw Error {ErrorType::GENERIC, program_->SourceFilePath().Utf8(), "declgen ets2ts: " + std::string(message),
112                 loc.line, loc.col};
113}
114
115const ir::Identifier *TSDeclGen::GetKeyIdent(const ir::Expression *key)
116{
117    if (!key->IsIdentifier()) {
118        ThrowError("Not identifier keys are not supported", key->Start());
119    }
120
121    return key->AsIdentifier();
122}
123
124static char const *GetDebugTypeName(const checker::Type *checkerType)
125{
126// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
127#define TYPE_CHECKS(type_flag, typeName) \
128    if (checkerType->Is##typeName()) {   \
129        return #typeName;                \
130    }
131    TYPE_MAPPING(TYPE_CHECKS)
132#undef TYPE_CHECKS
133    return "unknown type";
134}
135
136void TSDeclGen::GenType(const checker::Type *checkerType)
137{
138    DebugPrint("  GenType: ");
139#if DEBUG_PRINT
140    const auto var_name = checkerType->Variable() == nullptr ? "" : checkerType->Variable()->Name().Mutf8();
141    DebugPrint(std::string("  Converting type: ") + GetDebugTypeName(checkerType) + " (" + var_name + ")");
142#endif
143
144    if (checkerType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
145        Out("number");
146        return;
147    }
148    if (checkerType->HasTypeFlag(checker::TypeFlag::FUNCTION)) {
149        GenFunctionType(checkerType->AsETSFunctionType());
150        return;
151    }
152
153    switch (checker::ETSChecker::ETSType(checkerType)) {
154        case checker::TypeFlag::ETS_VOID:
155        case checker::TypeFlag::ETS_NULL:
156        case checker::TypeFlag::ETS_UNDEFINED:
157        case checker::TypeFlag::ETS_BOOLEAN:
158        case checker::TypeFlag::ETS_TYPE_PARAMETER:
159        case checker::TypeFlag::ETS_NONNULLISH:
160        case checker::TypeFlag::ETS_READONLY:
161        case checker::TypeFlag::ETS_INT_ENUM:
162            Out(checkerType->ToString());
163            return;
164        case checker::TypeFlag::ETS_OBJECT:
165        case checker::TypeFlag::ETS_DYNAMIC_TYPE:
166            GenObjectType(checkerType->AsETSObjectType());
167            return;
168        case checker::TypeFlag::ETS_ARRAY:
169            GenType(checkerType->AsETSArrayType()->ElementType());
170            Out("[]");
171            return;
172        case checker::TypeFlag::ETS_UNION:
173            GenUnionType(checkerType->AsETSUnionType());
174            return;
175        default:
176            ThrowError(std::string("Unsupported type: '") + GetDebugTypeName(checkerType));
177    }
178}
179
180void TSDeclGen::GenLiteral(const ir::Literal *literal)
181{
182    if (!literal->IsNumberLiteral()) {
183        ThrowError("Unsupported literal type", literal->Start());
184    }
185
186    const auto number = literal->AsNumberLiteral()->Number();
187    if (number.IsInt()) {
188        Out(std::to_string(number.GetInt()));
189        return;
190    }
191    if (number.IsLong()) {
192        Out(std::to_string(number.GetLong()));
193        return;
194    }
195    if (number.IsFloat()) {
196        Out(std::to_string(number.GetFloat()));
197        return;
198    }
199    if (number.IsDouble()) {
200        Out(std::to_string(number.GetDouble()));
201        return;
202    }
203
204    ThrowError("Unexpected number literal type", literal->Start());
205}
206
207void TSDeclGen::GenFunctionBody(const ir::MethodDefinition *methodDef, const checker::Signature *sig,
208                                const bool isConstructor, const bool isSetter)
209{
210    if (isConstructor) {
211        if (state_.super != nullptr) {
212            Out("{ super(...{} as (ConstructorParameters<typeof ");
213            GenType(state_.super->TsType());
214            Out(">)); }");
215        } else {
216            Out(" {}");
217        }
218    } else if (isSetter) {
219        Out(" {}");
220    } else {
221        Out(methodDef != nullptr ? ": " : " => ");
222        GenType(sig->ReturnType());
223        if (methodDef != nullptr && !state_.inInterface) {
224            Out(" { return {} as any; }");
225        }
226    }
227}
228
229void TSDeclGen::GenFunctionType(const checker::ETSFunctionType *etsFunctionType, const ir::MethodDefinition *methodDef)
230{
231    const bool isConstructor = methodDef != nullptr ? methodDef->IsConstructor() : false;
232    const bool isSetter = methodDef != nullptr ? methodDef->Kind() == ir::MethodDefinitionKind::SET : false;
233
234    const auto *sig = [this, methodDef, etsFunctionType]() -> const checker::Signature * {
235        if (methodDef != nullptr) {
236            return methodDef->Function()->Signature();
237        }
238        if (etsFunctionType->CallSignatures().size() != 1) {
239            const auto loc = methodDef != nullptr ? methodDef->Start() : lexer::SourcePosition();
240            ThrowError("Method overloads are not supported", loc);
241        }
242        return etsFunctionType->CallSignatures()[0];
243    }();
244
245    const auto *func = sig->Function();
246    GenTypeParameters(func->TypeParams());
247    Out("(");
248
249    GenSeparated(sig->Params(), [this](varbinder::LocalVariable *param) {
250        Out(param->Name());
251        const auto *paramType = param->TsType();
252
253        if (param->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
254            Out("?");
255        }
256        Out(": ");
257        GenType(paramType);
258    });
259
260    const auto *sigInfo = sig->GetSignatureInfo();
261    if (sigInfo->restVar != nullptr) {
262        if (!sig->Params().empty()) {
263            Out(", ");
264        }
265        Out("...", sigInfo->restVar->Name().Mutf8(), ": ");
266        GenType(sigInfo->restVar->TsType());
267    }
268
269    Out(")");
270
271    GenFunctionBody(methodDef, sig, isConstructor, isSetter);
272}
273
274void TSDeclGen::GenEnumType(const checker::ETSIntEnumType *enumType)
275{
276    for (auto *member : enumType->GetMembers()) {
277        Out(INDENT);
278        if (!member->IsTSEnumMember()) {
279            ThrowError("Member of enum not of type TSEnumMember", member->Start());
280        }
281
282        const auto *enumMember = member->AsTSEnumMember();
283        Out(GetKeyIdent(enumMember->Key())->Name().Mutf8());
284        const auto *init = enumMember->Init();
285        if (init != nullptr) {
286            Out(" = ");
287
288            if (!init->IsLiteral()) {
289                ThrowError("Only literal enum initializers are supported", member->Start());
290            }
291
292            GenLiteral(init->AsLiteral());
293        }
294
295        Out(",");
296        OutEndl();
297    }
298}
299
300void TSDeclGen::GenUnionType(const checker::ETSUnionType *unionType)
301{
302    GenSeparated(
303        unionType->ConstituentTypes(), [this](checker::Type *arg) { GenType(arg); }, " | ");
304}
305
306void TSDeclGen::GenObjectType(const checker::ETSObjectType *objectType)
307{
308    if (objectType->IsETSStringType()) {
309        Out("string");
310        return;
311    }
312    if (objectType->HasObjectFlag(checker::ETSObjectFlags::UNBOXABLE_TYPE)) {
313        Out("number");  // NOTE(ivagin): create precise builtin type
314        return;
315    }
316    if (objectType->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL)) {
317        const auto *invoke = objectType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(
318            checker::FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME);
319        ASSERT(invoke && invoke->TsType() && invoke->TsType()->IsETSFunctionType());
320        GenType(invoke->TsType());
321        return;
322    }
323    if (objectType->HasObjectFlag(checker::ETSObjectFlags::DYNAMIC)) {
324        Out("any");
325        return;
326    }
327
328    auto typeName = objectType->Name();
329    if (typeName.Empty()) {
330        Warning("Object type name is empty");
331        Out("any");
332    } else {
333        Out(typeName);
334    }
335
336    const auto &typeArgs = objectType->TypeArguments();
337    if (!typeArgs.empty()) {
338        Out("<");
339        GenSeparated(typeArgs, [this](checker::Type *arg) { GenType(arg); });
340        Out(">");
341    }
342}
343
344void TSDeclGen::GenTypeParameters(const ir::TSTypeParameterDeclaration *typeParams)
345{
346    if (typeParams != nullptr) {
347        Out("<");
348        GenSeparated(typeParams->Params(), [this](ir::TSTypeParameter *param) {
349            Out(param->Name()->Name());
350            auto *constraint = param->Constraint();
351            if (constraint != nullptr) {
352                Out(" extends ");
353                GenType(constraint->GetType(checker_));
354            }
355        });
356        Out(">");
357    }
358}
359
360void TSDeclGen::GenExport(const ir::Identifier *symbol)
361{
362    const auto symbolName = symbol->Name().Mutf8();
363    Out("export {", symbolName, "};");
364    OutEndl();
365    if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
366        Out("exports.", symbolName, " = ", symbolName, ";");
367    }
368    OutEndl();
369}
370
371void TSDeclGen::GenExport(const ir::Identifier *symbol, const std::string &alias)
372{
373    const auto symbolName = symbol->Name().Mutf8();
374    Out("export {", symbolName, " as ", alias, "};");
375    OutEndl();
376    if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
377        Out("exports.", alias, " = ", symbolName, ";");
378    }
379    OutEndl();
380}
381
382void TSDeclGen::GenDefaultExport(const ir::Identifier *symbol)
383{
384    const auto symbolName = symbol->Name().Mutf8();
385    Out("export default ", symbolName, ";");
386    OutEndl();
387    if (!symbol->Parent()->IsTSTypeAliasDeclaration() && !symbol->Parent()->IsTSInterfaceDeclaration()) {
388        Out("exports.default = ", symbolName, ";");
389    }
390    OutEndl();
391}
392
393void TSDeclGen::ExportIfNeeded(const ir::Identifier *symbol)
394{
395    if (symbol->Parent()->IsExported()) {
396        GenExport(symbol);
397    }
398    if (symbol->Parent()->IsExportedType()) {
399        GenExport(symbol);
400    }
401    if (symbol->Parent()->IsDefaultExported()) {
402        GenDefaultExport(symbol);
403    }
404}
405
406template <class T>
407void TSDeclGen::GenModifier(const T *node)
408{
409    if (state_.inInterface) {
410        return;
411    }
412
413    if (node->IsPrivate()) {
414        Out("private ");
415    }
416    if (node->IsProtected()) {
417        Out("protected ");
418    }
419    if (node->IsPublic()) {
420        Out("public ");
421    }
422    if (node->IsReadonly()) {
423        Out("readonly ");
424    }
425    if (node->IsStatic()) {
426        Out("static ");
427    }
428}
429
430void TSDeclGen::GenImportDeclaration(const ir::ETSImportDeclaration *importDeclaration)
431{
432    DebugPrint("GenImportDeclaration");
433    if (importDeclaration->IsPureDynamic()) {
434        return;
435    }
436
437    const auto &specifiers = importDeclaration->Specifiers();
438    Out("import { ");
439    GenSeparated(specifiers, [this, &importDeclaration](ir::AstNode *specifier) {
440        if (!specifier->IsImportSpecifier()) {
441            ThrowError("Only import specifiers are supported", importDeclaration->Start());
442        }
443
444        const auto local = specifier->AsImportSpecifier()->Local()->Name();
445        const auto imported = specifier->AsImportSpecifier()->Imported()->Name();
446        Out(local);
447        if (local != imported) {
448            ThrowError("Imports with local bindings are not supported", importDeclaration->Start());
449        }
450    });
451
452    auto source = importDeclaration->Source()->Str().Mutf8();
453    Out(" } from \"", source, "\";");
454    OutEndl(2U);
455}
456
457void TSDeclGen::GenTypeAliasDeclaration(const ir::TSTypeAliasDeclaration *typeAlias)
458{
459    const auto name = typeAlias->Id()->Name().Mutf8();
460    DebugPrint("GenTypeAliasDeclaration: " + name);
461    const auto *aliasedType = typeAlias->TypeAnnotation()->GetType(checker_);
462    Out("type ", name, " = ");
463    GenType(aliasedType);
464    Out(";");
465    OutEndl();
466
467    ExportIfNeeded(typeAlias->Id());
468    OutEndl();
469}
470
471void TSDeclGen::GenEnumDeclaration(const ir::TSEnumDeclaration *enumDecl)
472{
473    const auto enumIdent = GetKeyIdent(enumDecl->Key());
474    const auto enumName = enumIdent->Name().Mutf8();
475    DebugPrint("GenEnumDeclaration: " + enumName);
476    Out("enum ", enumName, " {");
477    OutEndl();
478
479    ASSERT(enumDecl->TsType()->IsETSIntEnumType());
480    GenEnumType(enumDecl->TsType()->AsETSIntEnumType());
481
482    Out("}");
483    OutEndl();
484
485    ExportIfNeeded(enumIdent);
486    OutEndl();
487}
488
489void TSDeclGen::GenInterfaceDeclaration(const ir::TSInterfaceDeclaration *interfaceDecl)
490{
491    state_.inInterface = true;
492    const auto interfaceName = interfaceDecl->Id()->Name().Mutf8();
493    DebugPrint("GenInterfaceDeclaration: " + interfaceName);
494    Out("interface ", interfaceName);
495
496    GenTypeParameters(interfaceDecl->TypeParams());
497
498    Out(" {");
499    OutEndl();
500
501    for (auto *prop : interfaceDecl->Body()->Body()) {
502        if (prop->IsMethodDefinition()) {
503            GenMethodDeclaration(prop->AsMethodDefinition());
504            for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
505                GenMethodDeclaration(methodDef);
506            }
507        }
508        if (prop->IsClassProperty()) {
509            GenPropDeclaration(prop->AsClassProperty());
510        }
511    }
512
513    Out("}");
514    OutEndl();
515
516    ExportIfNeeded(interfaceDecl->Id());
517    OutEndl();
518}
519
520void TSDeclGen::GenClassDeclaration(const ir::ClassDeclaration *classDecl)
521{
522    const auto *classDef = classDecl->Definition();
523    std::string classDescriptor = "L" + classDef->InternalName().Mutf8() + ";";
524    std::replace(classDescriptor.begin(), classDescriptor.end(), '.', '/');
525    state_.currentClassDescriptor = classDescriptor;
526    const auto className = classDef->Ident()->Name().Mutf8();
527    state_.inGlobalClass = classDef->IsGlobal();
528
529    DebugPrint("GenClassDeclaration: " + className);
530
531    if (className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS ||
532        className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos)) {
533        return;
534    }
535
536    if (!state_.inGlobalClass) {
537        Out("class ", className);
538        GenTypeParameters(classDef->TypeParams());
539
540        const auto *super = classDef->Super();
541        state_.super = super;
542        if (super != nullptr) {
543            Out(" extends ");
544            GenType(super->TsType());
545        }
546
547        const auto &interfaces = classDef->TsType()->AsETSObjectType()->Interfaces();
548        if (!interfaces.empty()) {
549            Out(" implements ");
550            ASSERT(classDef->TsType()->IsETSObjectType());
551            GenSeparated(interfaces, [this](checker::ETSObjectType *interface) { GenType(interface); });
552        }
553
554        Out(" {");
555        OutEndl();
556    }
557
558    for (const auto *prop : classDef->Body()) {
559        if (prop->IsMethodDefinition()) {
560            GenMethodDeclaration(prop->AsMethodDefinition());
561            for (const auto *methodDef : prop->AsMethodDefinition()->Overloads()) {
562                GenMethodDeclaration(methodDef);
563            }
564        } else if (prop->IsClassProperty()) {
565            GenPropDeclaration(prop->AsClassProperty());
566        }
567    }
568
569    if (!state_.inGlobalClass) {
570        Out("};");
571        OutEndl();
572        Out("(", className, " as any) = (globalThis as any).Panda.getClass('", state_.currentClassDescriptor, "');");
573        OutEndl();
574        ExportIfNeeded(classDef->Ident());
575        OutEndl();
576    }
577}
578
579void TSDeclGen::GenMethodDeclaration(const ir::MethodDefinition *methodDef)
580{
581    const auto methodIdent = GetKeyIdent(methodDef->Key());
582    const auto methodName = methodIdent->Name().Mutf8();
583    if (methodName.find('#') != std::string::npos) {
584        return;
585    }
586
587    if (state_.inGlobalClass) {
588        Out("function ");
589    } else {
590        Out(INDENT);
591        GenModifier(methodDef);
592    }
593
594    if (methodDef->Kind() == ir::MethodDefinitionKind::GET) {
595        Out("get ");
596    }
597    if (methodDef->Kind() == ir::MethodDefinitionKind::SET) {
598        Out("set ");
599    }
600
601    DebugPrint("  GenMethodDeclaration: " + methodName);
602    Out(methodName);
603
604    if (methodDef->TsType() == nullptr) {
605        Warning("Untyped method encountered: " + methodName);
606        Out(": any");
607    } else {
608        GenFunctionType(methodDef->TsType()->AsETSFunctionType(), methodDef);
609    }
610
611    Out(";");
612    OutEndl();
613
614    if (state_.inGlobalClass) {
615        Out("(", methodName, " as any) = ETSGLOBAL.", methodName, ";");
616        OutEndl();
617        ExportIfNeeded(methodIdent);
618        if (methodName == compiler::Signatures::INIT_METHOD) {
619            Out(methodName, "();");
620        }
621        OutEndl(2U);
622    }
623}
624
625void TSDeclGen::GenPropDeclaration(const ir::ClassProperty *classProp)
626{
627    if (state_.inGlobalClass) {
628        GenGlobalVarDeclaration(classProp);
629        return;
630    }
631
632    const auto propName = GetKeyIdent(classProp->Key())->Name().Mutf8();
633    DebugPrint("  GenPropDeclaration: " + propName);
634
635    Out(INDENT);
636    GenModifier(classProp);
637    Out(propName);
638
639    Out(": ");
640    GenType(classProp->TsType());
641    if (!state_.inInterface) {
642        Out(" = {} as any");
643    }
644    Out(";");
645    OutEndl();
646}
647
648void TSDeclGen::GenGlobalVarDeclaration(const ir::ClassProperty *globalVar)
649{
650    if (!globalVar->IsExported() && !globalVar->IsDefaultExported()) {
651        return;
652    }
653
654    const auto symbol = GetKeyIdent(globalVar->Key());
655    const auto varName = symbol->Name().Mutf8();
656    DebugPrint("GenGlobalVarDeclaration: " + varName);
657    if (!globalVar->IsConst()) {
658        Warning("Not constant global variables are not supported, variable \"" + varName + "\" was skipped");
659        return;
660    }
661
662    Out("const ", varName, ": ");
663    GenType(globalVar->TsType());
664    Out(" = ETSGLOBAL.", varName, ';');
665    OutEndl();
666
667    GenExport(symbol);
668    OutEndl();
669}
670
671bool GenerateTsDeclarations(checker::ETSChecker *checker, const ark::es2panda::parser::Program *program,
672                            const std::string &outPath)
673{
674    TSDeclGen declBuilder(checker, program);
675    declBuilder.Generate();
676
677    std::ofstream outStream(outPath);
678    if (outStream.fail()) {
679        std::cerr << "Failed to open file: " << outPath << std::endl;
680        return false;
681    }
682
683    outStream << declBuilder.Output().str();
684    outStream.close();
685
686    return true;
687}
688}  // namespace ark::es2panda::declgen_ets2ts
689