Coverage Report

Created: 2026-05-30 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flatbuffers/src/idl_gen_ts.cpp
Line
Count
Source
1
/*
2
 * Copyright 2014 Google Inc. All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "idl_gen_ts.h"
18
19
#include <algorithm>
20
#include <cassert>
21
#include <cmath>
22
#include <iostream>
23
#include <unordered_map>
24
#include <unordered_set>
25
26
#include "flatbuffers/code_generators.h"
27
#include "flatbuffers/flatbuffers.h"
28
#include "flatbuffers/flatc.h"
29
#include "flatbuffers/idl.h"
30
#include "flatbuffers/util.h"
31
#include "idl_namer.h"
32
33
namespace flatbuffers {
34
namespace {
35
struct ImportDefinition {
36
  std::string name;
37
  std::string import_statement;
38
  std::string export_statement;
39
  std::string bare_file_path;
40
  std::string rel_file_path;
41
  std::string object_name;
42
  const Definition* dependent = nullptr;
43
  const Definition* dependency = nullptr;
44
};
45
46
struct NsDefinition {
47
  std::string path;
48
  std::string filepath;
49
  std::string symbolic_name;
50
  const Namespace* ns = nullptr;
51
  std::map<std::string, const Definition*> definitions;
52
};
53
54
0
Namer::Config TypeScriptDefaultConfig() {
55
0
  return {/*types=*/Case::kKeep,
56
0
          /*constants=*/Case::kUnknown,
57
0
          /*methods=*/Case::kLowerCamel,
58
0
          /*functions=*/Case::kLowerCamel,
59
0
          /*fields=*/Case::kLowerCamel,
60
0
          /*variables=*/Case::kLowerCamel,
61
0
          /*variants=*/Case::kKeep,
62
0
          /*enum_variant_seperator=*/"::",
63
0
          /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
64
0
          /*namespaces=*/Case::kKeep,
65
0
          /*namespace_seperator=*/"_",
66
0
          /*object_prefix=*/"",
67
0
          /*object_suffix=*/"T",
68
0
          /*keyword_prefix=*/"",
69
0
          /*keyword_suffix=*/"_",
70
0
          /*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
71
0
          /*filenames=*/Case::kDasher,
72
0
          /*directories=*/Case::kDasher,
73
0
          /*output_path=*/"",
74
0
          /*filename_suffix=*/"_generated",
75
0
          /*filename_extension=*/".ts"};
76
0
}
77
78
0
std::set<std::string> TypescriptKeywords() {
79
  // List of keywords retrieved from here:
80
  // https://github.com/microsoft/TypeScript/issues/2536
81
0
  return {
82
0
      "arguments", "break",    "case",      "catch",      "class",      "const",
83
0
      "continue",  "debugger", "default",   "delete",     "do",         "else",
84
0
      "enum",      "export",   "extends",   "false",      "finally",    "for",
85
0
      "function",  "if",       "import",    "in",         "instanceof", "new",
86
0
      "null",      "Object",   "return",    "super",      "switch",     "this",
87
0
      "throw",     "true",     "try",       "typeof",     "var",        "void",
88
0
      "while",     "with",     "as",        "implements", "interface",  "let",
89
0
      "package",   "private",  "protected", "public",     "static",     "yield",
90
0
      "undefined"  // Used with --ts-undefined-for-optionals
91
0
  };
92
0
}
93
94
enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
95
96
template <typename T>
97
struct SupportsObjectAPI : std::false_type {};
98
99
template <>
100
struct SupportsObjectAPI<StructDef> : std::true_type {};
101
102
}  // namespace
103
104
namespace ts {
105
// Iterate through all definitions we haven't generate code for (enums, structs,
106
// and tables) and output them to a single file.
107
class TsGenerator : public BaseGenerator {
108
 public:
109
  typedef std::map<std::string, ImportDefinition> import_set;
110
111
  TsGenerator(const Parser& parser, const std::string& path,
112
              const std::string& file_name)
113
0
      : BaseGenerator(parser, path, file_name, "", "_", "ts"),
114
0
        namer_(WithFlagOptions(TypeScriptDefaultConfig(), parser.opts, path),
115
0
               TypescriptKeywords()),
116
0
        null_keyword_(parser_.opts.ts_undefined_for_optionals ? "undefined"
117
0
                                                              : "null") {}
118
119
0
  bool generate() {
120
0
    generateEnums();
121
0
    generateStructs();
122
0
    if (!parser_.opts.ts_omit_entrypoint) {
123
0
      generateEntry();
124
0
    }
125
0
    return true;
126
0
  }
127
128
  std::string GetTypeName(const EnumDef& def, const bool = false,
129
0
                          const bool force_ns_wrap = false) {
130
0
    if (force_ns_wrap) {
131
0
      return namer_.NamespacedType(def);
132
0
    }
133
0
    return namer_.Type(def);
134
0
  }
135
136
  std::string GetTypeName(const StructDef& def, const bool object_api = false,
137
0
                          const bool force_ns_wrap = false) {
138
0
    if (object_api && parser_.opts.generate_object_based_api) {
139
0
      if (force_ns_wrap) {
140
0
        return namer_.NamespacedObjectType(def);
141
0
      } else {
142
0
        return namer_.ObjectType(def);
143
0
      }
144
0
    } else {
145
0
      if (force_ns_wrap) {
146
0
        return namer_.NamespacedType(def);
147
0
      } else {
148
0
        return namer_.Type(def);
149
0
      }
150
0
    }
151
0
  }
152
153
  // Save out the generated code for a single class while adding
154
  // declaration boilerplate.
155
  bool SaveType(const Definition& definition, const std::string& class_code,
156
0
                import_set& imports, import_set& bare_imports) {
157
0
    if (!class_code.length()) return true;
158
159
0
    std::string code;
160
161
0
    code += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n" +
162
0
            "/* eslint-disable @typescript-eslint/no-unused-vars, "
163
0
            "@typescript-eslint/no-explicit-any, "
164
0
            "@typescript-eslint/no-non-null-assertion */\n\n";
165
166
0
    for (auto it = bare_imports.begin(); it != bare_imports.end(); it++) {
167
0
      code += it->second.import_statement + "\n";
168
0
    }
169
0
    if (!bare_imports.empty()) code += "\n";
170
171
0
    for (auto it = imports.begin(); it != imports.end(); it++) {
172
0
      if (it->second.dependency != &definition) {
173
0
        code += it->second.import_statement + "\n";
174
0
      }
175
0
    }
176
0
    if (!imports.empty()) code += "\n\n";
177
178
0
    code += class_code;
179
180
0
    auto dirs = namer_.Directories(*definition.defined_namespace);
181
0
    EnsureDirExists(dirs);
182
0
    auto basename = dirs + namer_.File(definition, SkipFile::Suffix);
183
184
0
    return parser_.opts.file_saver->SaveFile(basename.c_str(), code, false);
185
0
  }
186
187
0
  void TrackNsDef(const Definition& definition, std::string type_name) {
188
0
    std::string path;
189
0
    std::string filepath;
190
0
    std::string symbolic_name;
191
0
    if (definition.defined_namespace->components.size() > 0) {
192
0
      path = namer_.Directories(*definition.defined_namespace,
193
0
                                SkipDir::TrailingPathSeperator);
194
0
      filepath = path + ".ts";
195
0
      path = namer_.Directories(*definition.defined_namespace,
196
0
                                SkipDir::OutputPathAndTrailingPathSeparator);
197
0
      symbolic_name = definition.defined_namespace->components.back();
198
0
    } else {
199
0
      auto def_mod_name = namer_.File(definition, SkipFile::SuffixAndExtension);
200
0
      symbolic_name = file_name_;
201
0
      filepath = path_ + symbolic_name + ".ts";
202
0
    }
203
0
    if (ns_defs_.count(path) == 0) {
204
0
      NsDefinition nsDef;
205
0
      nsDef.path = path;
206
0
      nsDef.filepath = filepath;
207
0
      nsDef.ns = definition.defined_namespace;
208
0
      nsDef.definitions.insert(std::make_pair(type_name, &definition));
209
0
      nsDef.symbolic_name = symbolic_name;
210
0
      ns_defs_[path] = nsDef;
211
0
    } else {
212
0
      ns_defs_[path].definitions.insert(std::make_pair(type_name, &definition));
213
0
    }
214
0
  }
215
216
 private:
217
  IdlNamer namer_;
218
219
  std::map<std::string, NsDefinition> ns_defs_;
220
221
  std::string null_keyword_;
222
223
  // Generate code for all enums.
224
0
  void generateEnums() {
225
0
    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
226
0
         ++it) {
227
0
      import_set bare_imports;
228
0
      import_set imports;
229
0
      std::string enumcode;
230
0
      auto& enum_def = **it;
231
0
      GenEnum(enum_def, &enumcode, imports, false);
232
0
      GenEnum(enum_def, &enumcode, imports, true);
233
0
      std::string type_name = GetTypeName(enum_def);
234
0
      TrackNsDef(enum_def, type_name);
235
0
      SaveType(enum_def, enumcode, imports, bare_imports);
236
0
    }
237
0
  }
238
239
  // Generate code for all structs.
240
0
  void generateStructs() {
241
0
    for (auto it = parser_.structs_.vec.begin();
242
0
         it != parser_.structs_.vec.end(); ++it) {
243
0
      import_set bare_imports;
244
0
      import_set imports;
245
0
      AddImport(bare_imports, "* as flatbuffers", "flatbuffers");
246
0
      auto& struct_def = **it;
247
0
      std::string declcode;
248
0
      GenStruct(parser_, struct_def, &declcode, imports);
249
0
      std::string type_name = GetTypeName(struct_def);
250
0
      TrackNsDef(struct_def, type_name);
251
0
      SaveType(struct_def, declcode, imports, bare_imports);
252
0
    }
253
0
  }
254
255
  // Generate code for a single entry point module.
256
0
  void generateEntry() {
257
0
    std::string code;
258
259
    // add root namespace def if not already existing from defs tracking
260
0
    std::string root;
261
0
    if (ns_defs_.count(root) == 0) {
262
0
      NsDefinition nsDef;
263
0
      nsDef.path = root;
264
0
      nsDef.symbolic_name = file_name_;
265
0
      nsDef.filepath = path_ + file_name_ + ".ts";
266
0
      nsDef.ns = parser_.empty_namespace_;
267
0
      ns_defs_[nsDef.path] = nsDef;
268
0
    }
269
270
0
    for (const auto& it : ns_defs_) {
271
0
      code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n" +
272
0
             "/* eslint-disable @typescript-eslint/no-unused-vars, "
273
0
             "@typescript-eslint/no-explicit-any, "
274
0
             "@typescript-eslint/no-non-null-assertion */\n\n";
275
276
      // export all definitions in ns entry point module
277
0
      int export_counter = 0;
278
0
      for (const auto& def : it.second.definitions) {
279
0
        std::vector<std::string> rel_components;
280
        // build path for root level vs child level
281
0
        if (it.second.ns->components.size() > 0) {
282
0
          rel_components.push_back(it.second.ns->components.back());
283
0
        }
284
0
        auto base_file_name =
285
0
            namer_.File(*(def.second), SkipFile::SuffixAndExtension);
286
0
        auto base_name =
287
0
            namer_.Directories(it.second.ns->components, SkipDir::OutputPath) +
288
0
            base_file_name;
289
0
        auto ts_file_path = base_name + ".ts";
290
0
        auto base_name_rel = std::string("./");
291
0
        base_name_rel +=
292
0
            namer_.Directories(rel_components, SkipDir::OutputPath);
293
0
        base_name_rel += base_file_name;
294
0
        auto ts_file_path_rel = base_name_rel + ".ts";
295
0
        auto type_name = def.first;
296
0
        auto fully_qualified_type_name =
297
0
            it.second.ns->GetFullyQualifiedName(type_name);
298
0
        auto is_struct = parser_.structs_.Lookup(fully_qualified_type_name);
299
0
        code += "export { " + type_name;
300
0
        if (parser_.opts.generate_object_based_api && is_struct) {
301
0
          code += ", " + type_name + parser_.opts.object_suffix;
302
0
        }
303
0
        code += " } from '";
304
0
        std::string import_extension =
305
0
            parser_.opts.ts_no_import_ext ? "" : ".js";
306
0
        code += base_name_rel + import_extension + "';\n";
307
0
        export_counter++;
308
0
      }
309
310
      // re-export child namespace(s) in parent
311
0
      const auto child_ns_level = it.second.ns->components.size() + 1;
312
0
      for (const auto& it2 : ns_defs_) {
313
0
        if (it2.second.ns->components.size() != child_ns_level) continue;
314
0
        auto ts_file_path = it2.second.path + ".ts";
315
0
        code += "export * as " + it2.second.symbolic_name + " from './";
316
0
        int count = it2.second.ns->components.size() > 1 ? 2 : 1;
317
0
        std::vector<std::string> rel_path;
318
0
        std::copy(it2.second.ns->components.end() - count,
319
0
                  it2.second.ns->components.end(),
320
0
                  std::back_inserter(rel_path));
321
0
        code += namer_.Directories(
322
0
                    rel_path, SkipDir::OutputPathAndTrailingPathSeparator) +
323
0
                ".js';\n";
324
0
        export_counter++;
325
0
      }
326
327
0
      if (export_counter > 0) {
328
0
        parser_.opts.file_saver->SaveFile(it.second.filepath.c_str(), code,
329
0
                                          false);
330
0
      }
331
0
    }
332
0
  }
333
334
  // Generate a documentation comment, if available.
335
  static void GenDocComment(const std::vector<std::string>& dc,
336
                            std::string* code_ptr,
337
0
                            const char* indent = nullptr) {
338
0
    if (dc.empty()) {
339
      // Don't output empty comment blocks with 0 lines of comment content.
340
0
      return;
341
0
    }
342
343
0
    std::string& code = *code_ptr;
344
0
    if (indent) code += indent;
345
0
    code += "/**\n";
346
0
    for (auto it = dc.begin(); it != dc.end(); ++it) {
347
0
      if (indent) code += indent;
348
0
      std::string safe = *it;
349
0
      for (size_t pos = 0; (pos = safe.find("*/", pos)) != std::string::npos;) {
350
0
        safe.replace(pos, 2, "*\\/");
351
0
        pos += 3;
352
0
      }
353
0
      code += " *" + safe + "\n";
354
0
    }
355
0
    if (indent) code += indent;
356
0
    code += " */\n";
357
0
  }
358
359
0
  static void GenDocComment(std::string* code_ptr) {
360
0
    GenDocComment(std::vector<std::string>(), code_ptr);
361
0
  }
362
363
  // Generate an enum declaration and an enum string lookup table.
364
  void GenEnum(EnumDef& enum_def, std::string* code_ptr, import_set& imports,
365
0
               bool reverse) {
366
0
    if (enum_def.generated) return;
367
0
    if (reverse) return;  // FIXME.
368
0
    std::string& code = *code_ptr;
369
0
    GenDocComment(enum_def.doc_comment, code_ptr);
370
0
    code += "export enum ";
371
0
    code += GetTypeName(enum_def);
372
0
    code += " {\n";
373
0
    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
374
0
      auto& ev = **it;
375
0
      if (!ev.doc_comment.empty()) {
376
0
        if (it != enum_def.Vals().begin()) {
377
0
          code += '\n';
378
0
        }
379
0
        GenDocComment(ev.doc_comment, code_ptr, "  ");
380
0
      }
381
382
      // Generate mapping between EnumName: EnumValue(int)
383
0
      if (reverse) {
384
0
        code += "  '" + enum_def.ToString(ev) + "'";
385
0
        code += " = ";
386
0
        code += "'" + namer_.Variant(ev) + "'";
387
0
      } else {
388
0
        code += "  " + namer_.Variant(ev);
389
0
        code += " = ";
390
        // Unfortunately, because typescript does not support bigint enums,
391
        // for 64-bit enums, we instead map the enum names to strings.
392
0
        switch (enum_def.underlying_type.base_type) {
393
0
          case BASE_TYPE_LONG:
394
0
          case BASE_TYPE_ULONG: {
395
0
            code += "'" + enum_def.ToString(ev) + "'";
396
0
            break;
397
0
          }
398
0
          default:
399
0
            code += enum_def.ToString(ev);
400
0
        }
401
0
      }
402
403
0
      code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
404
0
    }
405
0
    code += "}";
406
407
0
    if (enum_def.is_union) {
408
0
      code += GenUnionConvFunc(enum_def.underlying_type, imports);
409
0
    }
410
411
0
    code += "\n";
412
0
  }
413
414
0
  static std::string GenType(const Type& type) {
415
0
    switch (type.base_type) {
416
0
      case BASE_TYPE_BOOL:
417
0
      case BASE_TYPE_CHAR:
418
0
        return "Int8";
419
0
      case BASE_TYPE_UTYPE:
420
0
        return GenType(GetUnionUnderlyingType(type));
421
0
      case BASE_TYPE_UCHAR:
422
0
        return "Uint8";
423
0
      case BASE_TYPE_SHORT:
424
0
        return "Int16";
425
0
      case BASE_TYPE_USHORT:
426
0
        return "Uint16";
427
0
      case BASE_TYPE_INT:
428
0
        return "Int32";
429
0
      case BASE_TYPE_UINT:
430
0
        return "Uint32";
431
0
      case BASE_TYPE_LONG:
432
0
        return "Int64";
433
0
      case BASE_TYPE_ULONG:
434
0
        return "Uint64";
435
0
      case BASE_TYPE_FLOAT:
436
0
        return "Float32";
437
0
      case BASE_TYPE_DOUBLE:
438
0
        return "Float64";
439
0
      case BASE_TYPE_STRING:
440
0
        return "String";
441
0
      case BASE_TYPE_VECTOR:
442
0
        return GenType(type.VectorType());
443
0
      case BASE_TYPE_STRUCT:
444
0
        return type.struct_def->name;
445
0
      default:
446
0
        return "flatbuffers.Table";
447
0
    }
448
0
  }
449
450
0
  std::string GenGetter(const Type& type, const std::string& arguments) {
451
0
    switch (type.base_type) {
452
0
      case BASE_TYPE_STRING:
453
0
        return GenBBAccess() + ".__string" + arguments;
454
0
      case BASE_TYPE_STRUCT:
455
0
        return GenBBAccess() + ".__struct" + arguments;
456
0
      case BASE_TYPE_UNION:
457
0
        if (!UnionHasStringType(*type.enum_def)) {
458
0
          return GenBBAccess() + ".__union" + arguments;
459
0
        }
460
0
        return GenBBAccess() + ".__union_with_string" + arguments;
461
0
      case BASE_TYPE_VECTOR:
462
0
        return GenGetter(type.VectorType(), arguments);
463
0
      default: {
464
0
        auto getter = GenBBAccess() + "." + "read" + GenType(type) + arguments;
465
0
        if (type.base_type == BASE_TYPE_BOOL) {
466
0
          getter = "!!" + getter;
467
0
        }
468
0
        return getter;
469
0
      }
470
0
    }
471
0
  }
472
473
0
  std::string GenBBAccess() const { return "this.bb!"; }
474
475
0
  std::string GenDefaultValue(const FieldDef& field, import_set& imports) {
476
0
    if (field.IsScalarOptional()) {
477
0
      return null_keyword_;
478
0
    }
479
480
0
    const auto& value = field.value;
481
0
    if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION &&
482
0
        value.type.base_type != BASE_TYPE_VECTOR) {
483
0
      switch (value.type.base_type) {
484
0
        case BASE_TYPE_ARRAY: {
485
0
          std::string ret = "[";
486
0
          for (auto i = 0; i < value.type.fixed_length; ++i) {
487
0
            std::string enum_name =
488
0
                AddImport(imports, *value.type.enum_def, *value.type.enum_def)
489
0
                    .name;
490
0
            const EnumVal* val =
491
0
                value.type.enum_def->FindByValue(value.constant);
492
0
            if (val == nullptr) {
493
0
              val = value.type.enum_def->MinValue();
494
0
            }
495
0
            std::string enum_value = namer_.Variant(*val);
496
0
            ret += enum_name + "." + enum_value +
497
0
                   (i < value.type.fixed_length - 1 ? ", " : "");
498
0
          }
499
0
          ret += "]";
500
0
          return ret;
501
0
        }
502
0
        case BASE_TYPE_LONG:
503
0
        case BASE_TYPE_ULONG: {
504
          // If the value is an enum with a 64-bit base type, we have to just
505
          // return the bigint value directly since typescript does not support
506
          // enums with bigint backing types.
507
0
          return "BigInt('" + value.constant + "')";
508
0
        }
509
0
        default: {
510
0
          const EnumVal* val = value.type.enum_def->FindByValue(value.constant);
511
0
          if (val == nullptr) {
512
0
            val = value.type.enum_def->MinValue();
513
0
          }
514
0
          return AddImport(imports, *value.type.enum_def, *value.type.enum_def)
515
0
                     .name +
516
0
                 "." + namer_.Variant(*val);
517
0
        }
518
0
      }
519
0
    }
520
521
0
    switch (value.type.base_type) {
522
0
      case BASE_TYPE_BOOL:
523
0
        return value.constant == "0" ? "false" : "true";
524
525
0
      case BASE_TYPE_STRING: {
526
        // NOTE: Strings without a default value are parsed as "0" by
527
        // the parser, so therefore we have to treat "0" as a null-signifying
528
        // value.
529
0
        if (value.constant == "0" || value.constant == "null") {
530
0
          return "null";
531
0
        } else {
532
0
          std::string escaped;
533
0
          flatbuffers::EscapeString(value.constant.c_str(),
534
0
                                    value.constant.length(), &escaped,
535
0
                                    true, false);
536
0
          return escaped;
537
0
        }
538
0
      }
539
0
      case BASE_TYPE_UNION:
540
0
      case BASE_TYPE_STRUCT: {
541
0
        return null_keyword_;
542
0
      }
543
544
0
      case BASE_TYPE_ARRAY:
545
0
      case BASE_TYPE_VECTOR:
546
0
        return "[]";
547
548
0
      case BASE_TYPE_LONG:
549
0
      case BASE_TYPE_ULONG: {
550
0
        return "BigInt('" + value.constant + "')";
551
0
      }
552
553
0
      default: {
554
0
        if (StringIsFlatbufferNan(value.constant)) {
555
0
          return "NaN";
556
0
        } else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
557
0
          return "Infinity";
558
0
        } else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
559
0
          return "-Infinity";
560
0
        }
561
0
        return value.constant;
562
0
      }
563
0
    }
564
0
  }
565
566
  std::string GenTypeName(import_set& imports, const Definition& owner,
567
                          const Type& type, bool input,
568
0
                          bool allowNull = false) {
569
0
    if (!input) {
570
0
      if (IsString(type) || type.base_type == BASE_TYPE_STRUCT) {
571
0
        std::string name;
572
0
        if (IsString(type)) {
573
0
          name = "string|Uint8Array";
574
0
        } else {
575
0
          name = AddImport(imports, owner, *type.struct_def).name;
576
0
        }
577
0
        return allowNull ? (name + "|" + null_keyword_) : name;
578
0
      }
579
0
    }
580
581
0
    switch (type.base_type) {
582
0
      case BASE_TYPE_BOOL:
583
0
        return allowNull ? ("boolean|" + null_keyword_) : "boolean";
584
0
      case BASE_TYPE_LONG:
585
0
      case BASE_TYPE_ULONG:
586
0
        return allowNull ? ("bigint|" + null_keyword_) : "bigint";
587
0
      case BASE_TYPE_ARRAY: {
588
0
        std::string name;
589
0
        if (type.element == BASE_TYPE_LONG || type.element == BASE_TYPE_ULONG) {
590
0
          name = "bigint[]";
591
0
        } else if (type.element != BASE_TYPE_STRUCT) {
592
0
          name = "number[]";
593
0
        } else {
594
0
          name = "any[]";
595
0
          if (parser_.opts.generate_object_based_api) {
596
0
            name = "(any|" +
597
0
                   GetTypeName(*type.struct_def, /*object_api =*/true) + ")[]";
598
0
          }
599
0
        }
600
601
0
        return name + (allowNull ? ("|" + null_keyword_) : "");
602
0
      }
603
0
      default:
604
0
        if (IsScalar(type.base_type)) {
605
0
          if (type.enum_def) {
606
0
            const auto enum_name =
607
0
                AddImport(imports, owner, *type.enum_def).name;
608
0
            return allowNull ? (enum_name + "|" + null_keyword_) : enum_name;
609
0
          }
610
0
          return allowNull ? ("number|" + null_keyword_) : "number";
611
0
        }
612
0
        return "flatbuffers.Offset";
613
0
    }
614
0
  }
615
616
0
  static Type GetUnionUnderlyingType(const Type& type) {
617
0
    if (type.enum_def != nullptr &&
618
0
        type.enum_def->underlying_type.base_type != type.base_type) {
619
0
      return type.enum_def->underlying_type;
620
0
    } else {
621
0
      return Type(BASE_TYPE_UCHAR);
622
0
    }
623
0
  }
624
625
0
  static Type GetUnderlyingVectorType(const Type& vector_type) {
626
0
    return (vector_type.base_type == BASE_TYPE_UTYPE)
627
0
               ? GetUnionUnderlyingType(vector_type)
628
0
               : vector_type;
629
0
  }
630
631
  // Returns the method name for use with add/put calls.
632
0
  std::string GenWriteMethod(const Type& type) {
633
    // Forward to signed versions since unsigned versions don't exist
634
0
    switch (type.base_type) {
635
0
      case BASE_TYPE_UTYPE:
636
0
        return GenWriteMethod(GetUnionUnderlyingType(type));
637
0
      case BASE_TYPE_UCHAR:
638
0
        return GenWriteMethod(Type(BASE_TYPE_CHAR));
639
0
      case BASE_TYPE_USHORT:
640
0
        return GenWriteMethod(Type(BASE_TYPE_SHORT));
641
0
      case BASE_TYPE_UINT:
642
0
        return GenWriteMethod(Type(BASE_TYPE_INT));
643
0
      case BASE_TYPE_ULONG:
644
0
        return GenWriteMethod(Type(BASE_TYPE_LONG));
645
0
      default:
646
0
        break;
647
0
    }
648
649
0
    return IsScalar(type.base_type) ? namer_.Type(GenType(type))
650
0
                                    : (IsStruct(type) ? "Struct" : "Offset");
651
0
  }
652
653
  template <typename T>
654
0
  static std::string MaybeAdd(T value) {
655
0
    return value != 0 ? " + " + NumToString(value) : "";
656
0
  }
657
658
  template <typename T>
659
0
  static std::string MaybeScale(T value) {
660
0
    return value != 1 ? " * " + NumToString(value) : "";
661
0
  }
662
663
  void GenStructArgs(import_set& imports, const StructDef& struct_def,
664
                     const Definition& owner, std::string* arguments,
665
0
                     const std::string& nameprefix) {
666
0
    for (auto it = struct_def.fields.vec.begin();
667
0
         it != struct_def.fields.vec.end(); ++it) {
668
0
      auto& field = **it;
669
0
      if (IsStruct(field.value.type)) {
670
        // Generate arguments for a struct inside a struct. To ensure names
671
        // don't clash, and to make it obvious these arguments are constructing
672
        // a nested struct, prefix the name with the field name.
673
0
        GenStructArgs(imports, *field.value.type.struct_def, owner, arguments,
674
0
                      nameprefix + field.name + "_");
675
0
      } else {
676
0
        *arguments += ", " + nameprefix + field.name + ": " +
677
0
                      GenTypeName(imports, owner, field.value.type, true,
678
0
                                  field.IsOptional());
679
0
      }
680
0
    }
681
0
  }
682
683
  void GenStructBody(const StructDef& struct_def, std::string* body,
684
0
                     const std::string& nameprefix) {
685
0
    *body += "  builder.prep(";
686
0
    *body += NumToString(struct_def.minalign) + ", ";
687
0
    *body += NumToString(struct_def.bytesize) + ");\n";
688
689
0
    for (auto it = struct_def.fields.vec.rbegin();
690
0
         it != struct_def.fields.vec.rend(); ++it) {
691
0
      auto& field = **it;
692
0
      if (field.padding) {
693
0
        *body += "  builder.pad(" + NumToString(field.padding) + ");\n";
694
0
      }
695
0
      if (IsStruct(field.value.type)) {
696
        // Generate arguments for a struct inside a struct. To ensure names
697
        // don't clash, and to make it obvious these arguments are constructing
698
        // a nested struct, prefix the name with the field name.
699
0
        GenStructBody(
700
0
            *field.value.type.struct_def, body,
701
0
            nameprefix.length() ? nameprefix + "_" + field.name : field.name);
702
0
      } else {
703
0
        auto element_type = field.value.type.element;
704
705
0
        if (field.value.type.base_type == BASE_TYPE_ARRAY) {
706
0
          switch (field.value.type.element) {
707
0
            case BASE_TYPE_STRUCT: {
708
0
              std::string str_last_item_idx =
709
0
                  NumToString(field.value.type.fixed_length - 1);
710
0
              *body += "\n  for (let i = " + str_last_item_idx +
711
0
                       "; i >= 0; --i" + ") {\n";
712
713
0
              std::string fname = nameprefix.length()
714
0
                                      ? nameprefix + "_" + field.name
715
0
                                      : field.name;
716
717
0
              *body += "    const item = " + fname + "?.[i];\n\n";
718
719
0
              if (parser_.opts.generate_object_based_api) {
720
0
                *body += "    if (item instanceof " +
721
0
                         GetTypeName(*field.value.type.struct_def,
722
0
                                     /*object_api =*/true) +
723
0
                         ") {\n";
724
0
                *body += "      item.pack(builder);\n";
725
0
                *body += "      continue;\n";
726
0
                *body += "    }\n\n";
727
0
              }
728
729
0
              std::string class_name =
730
0
                  GetPrefixedName(*field.value.type.struct_def);
731
0
              std::string pack_func_create_call =
732
0
                  class_name + ".create" + class_name + "(builder,\n";
733
0
              pack_func_create_call +=
734
0
                  "    " +
735
0
                  GenStructMemberValueTS(*field.value.type.struct_def, "item",
736
0
                                         ",\n    ", false) +
737
0
                  "\n  ";
738
0
              *body += "    " + pack_func_create_call;
739
0
              *body += "  );\n  }\n\n";
740
741
0
              break;
742
0
            }
743
0
            default: {
744
0
              std::string str_last_item_idx =
745
0
                  NumToString(field.value.type.fixed_length - 1);
746
0
              std::string fname = nameprefix.length()
747
0
                                      ? nameprefix + "_" + field.name
748
0
                                      : field.name;
749
750
0
              *body += "\n  for (let i = " + str_last_item_idx +
751
0
                       "; i >= 0; --i) {\n";
752
0
              *body += "    builder.write";
753
0
              *body += GenWriteMethod(
754
0
                  static_cast<flatbuffers::Type>(field.value.type.element));
755
0
              *body += "(";
756
0
              *body += element_type == BASE_TYPE_BOOL ? "+" : "";
757
758
0
              if (element_type == BASE_TYPE_LONG ||
759
0
                  element_type == BASE_TYPE_ULONG) {
760
0
                *body += "BigInt(" + fname + "?.[i] ?? 0));\n";
761
0
              } else {
762
0
                *body += "(" + fname + "?.[i] ?? 0));\n\n";
763
0
              }
764
0
              *body += "  }\n\n";
765
0
              break;
766
0
            }
767
0
          }
768
0
        } else {
769
0
          std::string fname =
770
0
              nameprefix.length() ? nameprefix + "_" + field.name : field.name;
771
772
0
          *body += "  builder.write" + GenWriteMethod(field.value.type) + "(";
773
0
          if (field.value.type.base_type == BASE_TYPE_BOOL) {
774
0
            *body += "Number(Boolean(" + fname + ")));\n";
775
0
            continue;
776
0
          } else if (field.value.type.base_type == BASE_TYPE_LONG ||
777
0
                     field.value.type.base_type == BASE_TYPE_ULONG) {
778
0
            *body += "BigInt(" + fname + " ?? 0));\n";
779
0
            continue;
780
0
          }
781
782
0
          *body += fname + ");\n";
783
0
        }
784
0
      }
785
0
    }
786
0
  }
787
788
0
  std::string GenerateNewExpression(const std::string& object_name) {
789
0
    return "new " + namer_.Type(object_name) + "()";
790
0
  }
791
792
  void GenerateRootAccessor(StructDef& struct_def, std::string* code_ptr,
793
                            std::string& code, const std::string& object_name,
794
0
                            bool size_prefixed) {
795
0
    if (!struct_def.fixed) {
796
0
      GenDocComment(code_ptr);
797
0
      std::string sizePrefixed("SizePrefixed");
798
0
      code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" +
799
0
              GetPrefixedName(struct_def, "As");
800
0
      code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
801
0
              "):" + object_name + " {\n";
802
0
      if (size_prefixed) {
803
0
        code +=
804
0
            "  bb.setPosition(bb.position() + "
805
0
            "flatbuffers.SIZE_PREFIX_LENGTH);\n";
806
0
      }
807
0
      code += "  return (obj || " + GenerateNewExpression(object_name);
808
0
      code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
809
0
      code += "}\n\n";
810
0
    }
811
0
  }
812
813
  void GenerateFinisher(StructDef& struct_def, std::string* code_ptr,
814
0
                        std::string& code, bool size_prefixed) {
815
0
    if (parser_.root_struct_def_ == &struct_def) {
816
0
      std::string sizePrefixed("SizePrefixed");
817
0
      GenDocComment(code_ptr);
818
819
0
      code += "static finish" + (size_prefixed ? sizePrefixed : "") +
820
0
              GetPrefixedName(struct_def) + "Buffer";
821
0
      code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
822
0
      code += "  builder.finish(offset";
823
0
      if (!parser_.file_identifier_.empty()) {
824
0
        code += ", '" + parser_.file_identifier_ + "'";
825
0
      }
826
0
      if (size_prefixed) {
827
0
        if (parser_.file_identifier_.empty()) {
828
0
          code += ", undefined";
829
0
        }
830
0
        code += ", true";
831
0
      }
832
0
      code += ");\n";
833
0
      code += "}\n\n";
834
0
    }
835
0
  }
836
837
0
  bool UnionHasStringType(const EnumDef& union_enum) {
838
0
    return std::any_of(union_enum.Vals().begin(), union_enum.Vals().end(),
839
0
                       [](const EnumVal* ev) {
840
0
                         return !ev->IsZero() && IsString(ev->union_type);
841
0
                       });
842
0
  }
843
844
0
  std::string GenUnionGenericTypeTS(const EnumDef& union_enum) {
845
    // TODO: make it work without any
846
    // return std::string("T") + (UnionHasStringType(union_enum) ? "|string" :
847
    // "");
848
0
    return std::string("any") +
849
0
           (UnionHasStringType(union_enum) ? "|string" : "");
850
0
  }
851
852
0
  std::string GenUnionTypeTS(const EnumDef& union_enum, import_set& imports) {
853
0
    std::string ret;
854
0
    std::set<std::string> type_list;
855
856
0
    for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
857
0
         ++it) {
858
0
      const auto& ev = **it;
859
0
      if (ev.IsZero()) {
860
0
        continue;
861
0
      }
862
863
0
      std::string type = "";
864
0
      if (IsString(ev.union_type)) {
865
0
        type = "string";  // no need to wrap string type in namespace
866
0
      } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
867
0
        type = AddImport(imports, union_enum, *ev.union_type.struct_def).name;
868
0
      } else {
869
0
        FLATBUFFERS_ASSERT(false);
870
0
      }
871
0
      type_list.insert(type);
872
0
    }
873
874
0
    for (auto it = type_list.begin(); it != type_list.end(); ++it) {
875
0
      ret += *it + ((std::next(it) == type_list.end()) ? "" : "|");
876
0
    }
877
878
0
    return ret;
879
0
  }
880
881
  static bool CheckIfNameClashes(const import_set& imports,
882
0
                                 const std::string& name) {
883
    // TODO: this would be better as a hashset.
884
0
    for (auto it = imports.begin(); it != imports.end(); it++) {
885
0
      if (it->second.name == name) {
886
0
        return true;
887
0
      }
888
0
    }
889
0
    return false;
890
0
  }
891
892
  std::string GenSymbolExpression(const StructDef& struct_def,
893
                                  const bool has_name_clash,
894
                                  const std::string& import_name,
895
                                  const std::string& name,
896
0
                                  const std::string& object_name) {
897
0
    std::string symbols_expression;
898
899
0
    if (has_name_clash) {
900
      // We have a name clash
901
0
      symbols_expression += import_name + " as " + name;
902
903
0
      if (parser_.opts.generate_object_based_api) {
904
0
        symbols_expression += ", " +
905
0
                              GetTypeName(struct_def, /*object_api =*/true) +
906
0
                              " as " + object_name;
907
0
      }
908
0
    } else {
909
      // No name clash, use the provided name
910
0
      symbols_expression += name;
911
912
0
      if (parser_.opts.generate_object_based_api) {
913
0
        symbols_expression += ", " + object_name;
914
0
      }
915
0
    }
916
917
0
    return symbols_expression;
918
0
  }
919
920
  std::string GenSymbolExpression(const EnumDef& enum_def,
921
                                  const bool has_name_clash,
922
                                  const std::string& import_name,
923
0
                                  const std::string& name, const std::string&) {
924
0
    std::string symbols_expression;
925
0
    if (has_name_clash) {
926
0
      symbols_expression += import_name + " as " + name;
927
0
    } else {
928
0
      symbols_expression += name;
929
0
    }
930
931
0
    if (enum_def.is_union) {
932
0
      symbols_expression += (", " + namer_.Function("unionTo" + name));
933
0
      symbols_expression += (", " + namer_.Function("unionListTo" + name));
934
0
    }
935
936
0
    return symbols_expression;
937
0
  }
938
939
0
  std::vector<std::string> PathComponents(const std::string& path) const {
940
0
    std::vector<std::string> components;
941
0
    size_t start = 0;
942
0
    while (start < path.size()) {
943
0
      auto end = path.find(kPathSeparator, start);
944
0
      if (end == std::string::npos) end = path.size();
945
0
      if (end > start) {
946
0
        components.emplace_back(path.substr(start, end - start));
947
0
      }
948
0
      if (end == path.size()) break;
949
0
      start = end + 1;
950
0
    }
951
0
    return components;
952
0
  }
953
954
  std::string RelativeDirectory(const std::vector<std::string>& from,
955
0
                                const std::vector<std::string>& to) const {
956
0
    size_t common = 0;
957
0
    while (common < from.size() && common < to.size() &&
958
0
           from[common] == to[common]) {
959
0
      ++common;
960
0
    }
961
962
0
    std::string rel;
963
0
    const size_t ups = from.size() - common;
964
0
    if (ups == 0) {
965
0
      rel = ".";
966
0
    } else {
967
0
      for (size_t i = 0; i < ups; ++i) {
968
0
        if (!rel.empty()) rel += kPathSeparator;
969
0
        rel += "..";
970
0
      }
971
0
    }
972
973
0
    for (size_t i = common; i < to.size(); ++i) {
974
0
      if (!rel.empty()) rel += kPathSeparator;
975
0
      rel += to[i];
976
0
    }
977
978
0
    return rel;
979
0
  }
980
981
  template <typename DefinitionT>
982
  ImportDefinition AddImport(import_set& imports, const Definition& dependent,
983
0
                             const DefinitionT& dependency) {
984
    // The unique name of the dependency, fully qualified in its namespace.
985
0
    const std::string unique_name = GetTypeName(
986
0
        dependency, /*object_api = */ false, /*force_ns_wrap=*/true);
987
988
    // Look if we have already added this import and return its name if found.
989
0
    const auto import_pair = imports.find(unique_name);
990
0
    if (import_pair != imports.end()) {
991
0
      return import_pair->second;
992
0
    }
993
994
    // Check if this name would have a name clash with another type. Just use
995
    // the "base" name (properly escaped) without any namespacing applied.
996
0
    const std::string import_name = GetTypeName(dependency);
997
0
    const bool has_name_clash = CheckIfNameClashes(imports, import_name);
998
999
    // If we have a name clash, use the unique name, otherwise use simple name.
1000
0
    std::string name = has_name_clash ? unique_name : import_name;
1001
1002
0
    const std::string object_name =
1003
0
        GetTypeName(dependency, /*object_api=*/true, has_name_clash);
1004
1005
0
    const std::string symbols_expression = GenSymbolExpression(
1006
0
        dependency, has_name_clash, import_name, name, object_name);
1007
1008
0
    const Namespace* dependent_ns = dependent.defined_namespace
1009
0
                                        ? dependent.defined_namespace
1010
0
                                        : parser_.empty_namespace_;
1011
0
    const Namespace* dependency_ns = dependency.defined_namespace
1012
0
                                         ? dependency.defined_namespace
1013
0
                                         : parser_.empty_namespace_;
1014
1015
0
    const std::string dependent_dirs =
1016
0
        namer_.Directories(*dependent_ns, SkipDir::OutputPath);
1017
0
    const std::string dependency_dirs =
1018
0
        namer_.Directories(*dependency_ns, SkipDir::OutputPath);
1019
1020
0
    const auto dependent_components = PathComponents(dependent_dirs);
1021
0
    const auto dependency_components = PathComponents(dependency_dirs);
1022
1023
0
    std::string rel_dir =
1024
0
        RelativeDirectory(dependent_components, dependency_components);
1025
0
    if (rel_dir.empty()) rel_dir = ".";
1026
0
    if (!rel_dir.empty()) rel_dir += kPathSeparator;
1027
1028
0
    std::string rel_file_path =
1029
0
        rel_dir + namer_.File(dependency, SkipFile::SuffixAndExtension);
1030
1031
0
    std::string bare_file_path =
1032
0
        kPathSeparator + dependency_dirs +
1033
0
        namer_.File(dependency, SkipFile::SuffixAndExtension);
1034
1035
0
    ImportDefinition import;
1036
0
    import.name = name;
1037
0
    import.object_name = object_name;
1038
0
    import.bare_file_path = bare_file_path;
1039
0
    import.rel_file_path = rel_file_path;
1040
0
    std::string import_extension = parser_.opts.ts_no_import_ext ? "" : ".js";
1041
0
    import.import_statement = "import { " + symbols_expression + " } from '" +
1042
0
                              rel_file_path + import_extension + "';";
1043
0
    import.export_statement = "export { " + symbols_expression + " } from '." +
1044
0
                              bare_file_path + import_extension + "';";
1045
0
    import.dependency = &dependency;
1046
0
    import.dependent = &dependent;
1047
1048
0
    imports.insert(std::make_pair(unique_name, import));
1049
1050
0
    return import;
1051
0
  }
Unexecuted instantiation: idl_gen_ts.cpp:flatbuffers::(anonymous namespace)::ImportDefinition flatbuffers::ts::TsGenerator::AddImport<flatbuffers::StructDef>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, flatbuffers::(anonymous namespace)::ImportDefinition, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, flatbuffers::(anonymous namespace)::ImportDefinition> > >&, flatbuffers::Definition const&, flatbuffers::StructDef const&)
Unexecuted instantiation: idl_gen_ts.cpp:flatbuffers::(anonymous namespace)::ImportDefinition flatbuffers::ts::TsGenerator::AddImport<flatbuffers::EnumDef>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, flatbuffers::(anonymous namespace)::ImportDefinition, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, flatbuffers::(anonymous namespace)::ImportDefinition> > >&, flatbuffers::Definition const&, flatbuffers::EnumDef const&)
1052
1053
  void AddImport(import_set& imports, std::string import_name,
1054
0
                 std::string fileName) {
1055
0
    ImportDefinition import;
1056
0
    import.name = import_name;
1057
0
    import.import_statement =
1058
0
        "import " + import_name + " from '" + fileName + "';";
1059
0
    imports.insert(std::make_pair(import_name, import));
1060
0
  }
1061
1062
  // Generate a TS union type based on a union's enum
1063
  std::string GenObjApiUnionTypeTS(import_set& imports,
1064
                                   const StructDef& dependent,
1065
                                   const IDLOptions&,
1066
0
                                   const EnumDef& union_enum) {
1067
0
    std::string ret = "";
1068
0
    std::set<std::string> type_list;
1069
1070
0
    for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
1071
0
         ++it) {
1072
0
      const auto& ev = **it;
1073
0
      if (ev.IsZero()) {
1074
0
        continue;
1075
0
      }
1076
1077
0
      std::string type = "";
1078
0
      if (IsString(ev.union_type)) {
1079
0
        type = "string";  // no need to wrap string type in namespace
1080
0
      } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1081
0
        type = AddImport(imports, dependent, *ev.union_type.struct_def)
1082
0
                   .object_name;
1083
0
      } else {
1084
0
        FLATBUFFERS_ASSERT(false);
1085
0
      }
1086
0
      type_list.insert(type);
1087
0
    }
1088
1089
0
    size_t totalPrinted = 0;
1090
0
    for (auto it = type_list.begin(); it != type_list.end(); ++it) {
1091
0
      ++totalPrinted;
1092
0
      ret += *it + ((totalPrinted == type_list.size()) ? "" : "|");
1093
0
    }
1094
1095
0
    return ret;
1096
0
  }
1097
1098
0
  std::string GenUnionConvFuncName(const EnumDef& enum_def) {
1099
0
    return namer_.Function("unionTo", enum_def);
1100
0
  }
1101
1102
0
  std::string GenUnionListConvFuncName(const EnumDef& enum_def) {
1103
0
    return namer_.Function("unionListTo", enum_def);
1104
0
  }
1105
1106
0
  std::string GenUnionConvFunc(const Type& union_type, import_set& imports) {
1107
0
    if (union_type.enum_def) {
1108
0
      const auto& enum_def = *union_type.enum_def;
1109
1110
0
      const auto valid_union_type = GenUnionTypeTS(enum_def, imports);
1111
0
      const auto valid_union_type_with_null =
1112
0
          valid_union_type + "|" + null_keyword_;
1113
1114
0
      auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) +
1115
0
                 "(\n  type: " + GetTypeName(enum_def) +
1116
0
                 ",\n  accessor: (obj:" + valid_union_type + ") => " +
1117
0
                 valid_union_type_with_null +
1118
0
                 "\n): " + valid_union_type_with_null + " {\n";
1119
1120
0
      const auto enum_type = AddImport(imports, enum_def, enum_def).name;
1121
1122
0
      const auto union_enum_loop = [&](const std::string& accessor_str) {
1123
0
        ret += "  switch(" + enum_type + "[type]) {\n";
1124
0
        ret += "    case 'NONE': return " + null_keyword_ + "; \n";
1125
1126
0
        for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1127
0
             ++it) {
1128
0
          const auto& ev = **it;
1129
0
          if (ev.IsZero()) {
1130
0
            continue;
1131
0
          }
1132
1133
0
          ret += "    case '" + namer_.Variant(ev) + "': ";
1134
1135
0
          if (IsString(ev.union_type)) {
1136
0
            ret += "return " + accessor_str + "'') as string;";
1137
0
          } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1138
0
            const auto type =
1139
0
                AddImport(imports, enum_def, *ev.union_type.struct_def).name;
1140
0
            ret += "return " + accessor_str + "new " + type + "())! as " +
1141
0
                   type + ";";
1142
0
          } else {
1143
0
            FLATBUFFERS_ASSERT(false);
1144
0
          }
1145
0
          ret += "\n";
1146
0
        }
1147
1148
0
        ret += "    default: return " + null_keyword_ + ";\n";
1149
0
        ret += "  }\n";
1150
0
      };
1151
1152
0
      union_enum_loop("accessor(");
1153
0
      ret += "}";
1154
1155
0
      ret += "\n\nexport function " + GenUnionListConvFuncName(enum_def) +
1156
0
             "(\n  type: " + GetTypeName(enum_def) +
1157
0
             ", \n  accessor: (index: number, obj:" + valid_union_type +
1158
0
             ") => " + valid_union_type_with_null +
1159
0
             ", \n  index: number\n): " + valid_union_type_with_null + " {\n";
1160
0
      union_enum_loop("accessor(index, ");
1161
0
      ret += "}";
1162
1163
0
      return ret;
1164
0
    }
1165
0
    FLATBUFFERS_ASSERT(0);
1166
0
    return "";
1167
0
  }
1168
1169
  // Used for generating a short function that returns the correct class
1170
  // based on union enum type. Assume the context is inside the non object api
1171
  // type
1172
  std::string GenUnionValTS(import_set& imports, const StructDef& dependent,
1173
                            const std::string& field_name,
1174
                            const Type& union_type,
1175
0
                            const bool is_array = false) {
1176
0
    if (union_type.enum_def) {
1177
0
      const auto& enum_def = *union_type.enum_def;
1178
0
      const auto enum_type = AddImport(imports, dependent, enum_def).name;
1179
0
      const std::string union_accessor = "this." + field_name;
1180
1181
0
      const auto union_has_string = UnionHasStringType(enum_def);
1182
0
      const auto field_binded_method = "this." + field_name + ".bind(this)";
1183
1184
0
      std::string ret;
1185
1186
0
      if (!is_array) {
1187
0
        const auto conversion_function = GenUnionConvFuncName(enum_def);
1188
1189
0
        ret = "(() => {\n";
1190
0
        ret += "      const temp = " + conversion_function + "(this." +
1191
0
               namer_.Method(field_name, "Type") + "(), " +
1192
0
               field_binded_method + ");\n";
1193
0
        ret += "      if(temp === " + null_keyword_ + ") { return " +
1194
0
               null_keyword_ + "; }\n";
1195
0
        ret += union_has_string
1196
0
                   ? "      if(typeof temp === 'string') { return temp; }\n"
1197
0
                   : "";
1198
0
        ret += "      return temp.unpack()\n";
1199
0
        ret += "  })()";
1200
0
      } else {
1201
0
        const auto conversion_function = GenUnionListConvFuncName(enum_def);
1202
1203
0
        ret = "(() => {\n";
1204
0
        ret += "    const ret: (" +
1205
0
               GenObjApiUnionTypeTS(imports, *union_type.struct_def,
1206
0
                                    parser_.opts, *union_type.enum_def) +
1207
0
               ")[] = [];\n";
1208
0
        ret += "    for(let targetEnumIndex = 0; targetEnumIndex < this." +
1209
0
               namer_.Method(field_name, "TypeLength") + "()" +
1210
0
               "; "
1211
0
               "++targetEnumIndex) {\n";
1212
0
        ret += "      const targetEnum = this." +
1213
0
               namer_.Method(field_name, "Type") + "(targetEnumIndex);\n";
1214
0
        ret += "      if(targetEnum === " + null_keyword_ + " || " + enum_type +
1215
0
               "[targetEnum!] === 'NONE') { "
1216
0
               "continue; }\n\n";
1217
0
        ret += "      const temp = " + conversion_function + "(targetEnum, " +
1218
0
               field_binded_method + ", targetEnumIndex);\n";
1219
0
        ret += "      if(temp === " + null_keyword_ + ") { continue; }\n";
1220
0
        ret += union_has_string ? "      if(typeof temp === 'string') { "
1221
0
                                  "ret.push(temp); continue; }\n"
1222
0
                                : "";
1223
0
        ret += "      ret.push(temp.unpack());\n";
1224
0
        ret += "    }\n";
1225
0
        ret += "    return ret;\n";
1226
0
        ret += "  })()";
1227
0
      }
1228
1229
0
      return ret;
1230
0
    }
1231
1232
0
    FLATBUFFERS_ASSERT(0);
1233
0
    return "";
1234
0
  }
1235
1236
  std::string GenNullCheckConditional(const std::string& nullCheckVar,
1237
                                      const std::string& trueVal,
1238
0
                                      const std::string& falseVal = "") {
1239
0
    std::string false_val = falseVal.empty() ? null_keyword_ : falseVal;
1240
0
    return "(" + nullCheckVar + " !== " + null_keyword_ + " ? " + trueVal +
1241
0
           " : " + false_val + ")";
1242
0
  }
1243
1244
  std::string GenStructMemberValueTS(const StructDef& struct_def,
1245
                                     const std::string& prefix,
1246
                                     const std::string& delimiter,
1247
0
                                     const bool nullCheck = true) {
1248
0
    std::string ret;
1249
0
    for (auto it = struct_def.fields.vec.begin();
1250
0
         it != struct_def.fields.vec.end(); ++it) {
1251
0
      auto& field = **it;
1252
1253
0
      auto curr_member_accessor = prefix + "." + namer_.Method(field);
1254
0
      if (prefix != "this") {
1255
0
        curr_member_accessor = prefix + "?." + namer_.Method(field);
1256
0
      }
1257
0
      if (IsStruct(field.value.type)) {
1258
0
        ret += GenStructMemberValueTS(*field.value.type.struct_def,
1259
0
                                      curr_member_accessor, delimiter);
1260
0
      } else {
1261
0
        if (nullCheck) {
1262
0
          std::string nullValue = "0";
1263
0
          if (field.value.type.base_type == BASE_TYPE_BOOL) {
1264
0
            nullValue = "false";
1265
0
          } else if (field.value.type.base_type == BASE_TYPE_LONG ||
1266
0
                     field.value.type.base_type == BASE_TYPE_ULONG) {
1267
0
            nullValue = "BigInt(0)";
1268
0
          } else if (field.value.type.base_type == BASE_TYPE_ARRAY) {
1269
0
            nullValue = "[]";
1270
0
          }
1271
0
          ret += "(" + curr_member_accessor + " ?? " + nullValue + ")";
1272
0
        } else {
1273
0
          ret += curr_member_accessor;
1274
0
        }
1275
0
      }
1276
1277
0
      if (std::next(it) != struct_def.fields.vec.end()) {
1278
0
        ret += delimiter;
1279
0
      }
1280
0
    }
1281
1282
0
    return ret;
1283
0
  }
1284
1285
  void GenObjApi(const Parser& parser, StructDef& struct_def,
1286
                 std::string& obj_api_unpack_func, std::string& obj_api_class,
1287
0
                 import_set& imports) {
1288
0
    const auto class_name = GetTypeName(struct_def, /*object_api=*/true);
1289
1290
0
    std::string unpack_func = "\nunpack(): " + class_name +
1291
0
                              " {\n  return new " + class_name + "(" +
1292
0
                              (struct_def.fields.vec.empty() ? "" : "\n");
1293
0
    std::string unpack_to_func = "\nunpackTo(_o: " + class_name + "): void {" +
1294
0
                                 +(struct_def.fields.vec.empty() ? "" : "\n");
1295
1296
0
    std::string constructor_func = "constructor(";
1297
0
    constructor_func += (struct_def.fields.vec.empty() ? "" : "\n");
1298
1299
0
    const auto has_create =
1300
0
        struct_def.fixed || CanCreateFactoryMethod(struct_def);
1301
1302
0
    std::string pack_func_prototype =
1303
0
        "\npack(builder:flatbuffers.Builder): flatbuffers.Offset {\n";
1304
1305
0
    std::string pack_func_offset_decl;
1306
0
    std::string pack_func_create_call;
1307
1308
0
    const auto struct_name = AddImport(imports, struct_def, struct_def).name;
1309
1310
0
    if (has_create) {
1311
0
      pack_func_create_call = "  return " + struct_name + ".create" +
1312
0
                              GetPrefixedName(struct_def) + "(builder" +
1313
0
                              (struct_def.fields.vec.empty() ? "" : ",\n    ");
1314
0
    } else {
1315
0
      pack_func_create_call = "  " + struct_name + ".start" +
1316
0
                              GetPrefixedName(struct_def) + "(builder);\n";
1317
0
    }
1318
1319
0
    if (struct_def.fixed) {
1320
      // when packing struct, nested struct's members instead of the struct's
1321
      // offset are used
1322
0
      pack_func_create_call +=
1323
0
          GenStructMemberValueTS(struct_def, "this", ",\n    ", false) + "\n  ";
1324
0
    }
1325
1326
0
    for (auto it = struct_def.fields.vec.begin();
1327
0
         it != struct_def.fields.vec.end(); ++it) {
1328
0
      auto& field = **it;
1329
0
      if (field.deprecated) continue;
1330
1331
0
      const auto field_method = namer_.Method(field);
1332
0
      const auto field_field = namer_.Field(field);
1333
0
      const std::string field_binded_method =
1334
0
          "this." + field_method + ".bind(this)";
1335
1336
0
      std::string field_val;
1337
0
      std::string field_type;
1338
      // a string that declares a variable containing the
1339
      // offset for things that can't be generated inline
1340
      // empty otw
1341
0
      std::string field_offset_decl;
1342
      // a string that contains values for things that can be created inline or
1343
      // the variable name from field_offset_decl
1344
0
      std::string field_offset_val;
1345
0
      const auto field_default_val = GenDefaultValue(field, imports);
1346
1347
      // Emit a scalar field
1348
0
      const auto is_string = IsString(field.value.type);
1349
0
      if (IsScalar(field.value.type.base_type) || is_string) {
1350
0
        field_type +=
1351
0
            GenTypeName(imports, field, field.value.type, false,
1352
0
                        !HasDefaultValue(field) || HasNullDefault(field));
1353
0
        field_val = "this." + namer_.Method(field) + "()";
1354
1355
0
        if (field.value.type.base_type != BASE_TYPE_STRING) {
1356
0
          field_offset_val = "this." + namer_.Field(field);
1357
0
        } else {
1358
0
          field_offset_decl = GenNullCheckConditional(
1359
0
              "this." + namer_.Field(field),
1360
0
              "builder.createString(this." + field_field + "!)", "0");
1361
0
        }
1362
0
      }
1363
1364
      // Emit an object field
1365
0
      else {
1366
0
        auto is_vector = false;
1367
0
        switch (field.value.type.base_type) {
1368
0
          case BASE_TYPE_STRUCT: {
1369
0
            const auto& sd = *field.value.type.struct_def;
1370
0
            field_type += AddImport(imports, struct_def, sd).object_name;
1371
1372
0
            const std::string field_accessor =
1373
0
                "this." + namer_.Method(field) + "()";
1374
0
            field_val = GenNullCheckConditional(
1375
0
                field_accessor, field_accessor + "!.unpack()", null_keyword_);
1376
0
            auto packing = GenNullCheckConditional(
1377
0
                "this." + field_field,
1378
0
                "this." + field_field + "!.pack(builder)", "0");
1379
1380
0
            if (sd.fixed) {
1381
0
              field_offset_val = std::move(packing);
1382
0
            } else {
1383
0
              field_offset_decl = std::move(packing);
1384
0
            }
1385
1386
0
            break;
1387
0
          }
1388
1389
0
          case BASE_TYPE_ARRAY: {
1390
0
            auto vectortype = field.value.type.VectorType();
1391
0
            auto vectortypename =
1392
0
                GenTypeName(imports, struct_def, vectortype, false);
1393
0
            is_vector = true;
1394
1395
0
            field_type = "(";
1396
1397
0
            switch (vectortype.base_type) {
1398
0
              case BASE_TYPE_STRUCT: {
1399
0
                const auto& sd = *field.value.type.struct_def;
1400
0
                const auto field_type_name =
1401
0
                    GetTypeName(sd, /*object_api=*/true);
1402
0
                field_type += field_type_name;
1403
0
                field_type += ")[]";
1404
1405
0
                field_val = GenBBAccess() + ".createObjList<" + vectortypename +
1406
0
                            ", " + field_type_name + ">(" +
1407
0
                            field_binded_method + ", " +
1408
0
                            NumToString(field.value.type.fixed_length) + ")";
1409
1410
0
                if (sd.fixed) {
1411
0
                  field_offset_decl =
1412
0
                      "builder.createStructOffsetList(this." + field_field +
1413
0
                      ", " + AddImport(imports, struct_def, struct_def).name +
1414
0
                      "." + namer_.Method("start", field, "Vector") + ")";
1415
0
                } else {
1416
0
                  field_offset_decl =
1417
0
                      AddImport(imports, struct_def, struct_def).name + "." +
1418
0
                      namer_.Method("create", field, "Vector") +
1419
0
                      "(builder, builder.createObjectOffsetList(" + "this." +
1420
0
                      field_field + "))";
1421
0
                }
1422
1423
0
                break;
1424
0
              }
1425
1426
0
              case BASE_TYPE_STRING: {
1427
0
                field_type += "string)[]";
1428
0
                field_val = GenBBAccess() + ".createScalarList<string>(" +
1429
0
                            field_binded_method + ", this." +
1430
0
                            namer_.Field(field, "Length") + "())";
1431
0
                field_offset_decl =
1432
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1433
0
                    namer_.Method("create", field, "Vector") +
1434
0
                    "(builder, builder.createObjectOffsetList(" + "this." +
1435
0
                    namer_.Field(field) + "))";
1436
0
                break;
1437
0
              }
1438
1439
0
              case BASE_TYPE_UNION: {
1440
0
                field_type += GenObjApiUnionTypeTS(
1441
0
                    imports, struct_def, parser.opts, *(vectortype.enum_def));
1442
0
                field_type += ")[]";
1443
0
                field_val = GenUnionValTS(imports, struct_def, field_method,
1444
0
                                          vectortype, true);
1445
1446
0
                field_offset_decl =
1447
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1448
0
                    namer_.Method("create", field, "Vector") +
1449
0
                    "(builder, builder.createObjectOffsetList(" + "this." +
1450
0
                    namer_.Field(field) + "))";
1451
1452
0
                break;
1453
0
              }
1454
0
              default: {
1455
0
                if (vectortype.enum_def) {
1456
0
                  field_type += GenTypeName(imports, struct_def, vectortype,
1457
0
                                            false, HasNullDefault(field));
1458
0
                } else {
1459
0
                  field_type += vectortypename;
1460
0
                }
1461
0
                field_type += ")[]";
1462
0
                field_val = GenBBAccess() + ".createScalarList<" +
1463
0
                            vectortypename + ">(" + field_binded_method + ", " +
1464
0
                            NumToString(field.value.type.fixed_length) + ")";
1465
1466
0
                field_offset_decl =
1467
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1468
0
                    namer_.Method("create", field, "Vector") +
1469
0
                    "(builder, this." + field_field + ")";
1470
1471
0
                break;
1472
0
              }
1473
0
            }
1474
1475
0
            break;
1476
0
          }
1477
1478
0
          case BASE_TYPE_VECTOR: {
1479
0
            auto vectortype = field.value.type.VectorType();
1480
0
            auto vectortypename =
1481
0
                GenTypeName(imports, struct_def, vectortype, false);
1482
0
            is_vector = true;
1483
1484
0
            field_type = "(";
1485
1486
0
            switch (vectortype.base_type) {
1487
0
              case BASE_TYPE_STRUCT: {
1488
0
                const auto& sd = *field.value.type.struct_def;
1489
0
                const auto field_type_name =
1490
0
                    GetTypeName(sd, /*object_api=*/true);
1491
0
                field_type += field_type_name;
1492
0
                field_type += ")[]";
1493
1494
0
                field_val = GenBBAccess() + ".createObjList<" + vectortypename +
1495
0
                            ", " + field_type_name + ">(" +
1496
0
                            field_binded_method + ", this." +
1497
0
                            namer_.Method(field, "Length") + "())";
1498
1499
0
                if (sd.fixed) {
1500
0
                  field_offset_decl =
1501
0
                      "builder.createStructOffsetList(this." + field_field +
1502
0
                      ", " + AddImport(imports, struct_def, struct_def).name +
1503
0
                      "." + namer_.Method("start", field, "Vector") + ")";
1504
0
                } else {
1505
0
                  field_offset_decl =
1506
0
                      AddImport(imports, struct_def, struct_def).name + "." +
1507
0
                      namer_.Method("create", field, "Vector") +
1508
0
                      "(builder, builder.createObjectOffsetList(" + "this." +
1509
0
                      field_field + "))";
1510
0
                }
1511
1512
0
                break;
1513
0
              }
1514
1515
0
              case BASE_TYPE_STRING: {
1516
0
                field_type += "string)[]";
1517
0
                field_val = GenBBAccess() + ".createScalarList<string>(" +
1518
0
                            field_binded_method + ", this." +
1519
0
                            namer_.Field(field, "Length") + "())";
1520
0
                field_offset_decl =
1521
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1522
0
                    namer_.Method("create", field, "Vector") +
1523
0
                    "(builder, builder.createObjectOffsetList(" + "this." +
1524
0
                    namer_.Field(field) + "))";
1525
0
                break;
1526
0
              }
1527
1528
0
              case BASE_TYPE_UNION: {
1529
0
                field_type += GenObjApiUnionTypeTS(
1530
0
                    imports, struct_def, parser.opts, *(vectortype.enum_def));
1531
0
                field_type += ")[]";
1532
0
                field_val = GenUnionValTS(imports, struct_def, field_method,
1533
0
                                          vectortype, true);
1534
1535
0
                field_offset_decl =
1536
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1537
0
                    namer_.Method("create", field, "Vector") +
1538
0
                    "(builder, builder.createObjectOffsetList(" + "this." +
1539
0
                    namer_.Field(field) + "))";
1540
1541
0
                break;
1542
0
              }
1543
0
              default: {
1544
0
                if (vectortype.enum_def) {
1545
0
                  field_type += GenTypeName(imports, struct_def, vectortype,
1546
0
                                            false, HasNullDefault(field));
1547
0
                } else {
1548
0
                  field_type += vectortypename;
1549
0
                }
1550
0
                field_type += ")[]";
1551
0
                field_val = GenBBAccess() + ".createScalarList<" +
1552
0
                            vectortypename + ">(" + field_binded_method +
1553
0
                            ", this." + namer_.Method(field, "Length") + "())";
1554
1555
0
                field_offset_decl =
1556
0
                    AddImport(imports, struct_def, struct_def).name + "." +
1557
0
                    namer_.Method("create", field, "Vector") +
1558
0
                    "(builder, this." + field_field + ")";
1559
1560
0
                break;
1561
0
              }
1562
0
            }
1563
1564
0
            break;
1565
0
          }
1566
1567
0
          case BASE_TYPE_UNION: {
1568
0
            field_type += GenObjApiUnionTypeTS(imports, struct_def, parser.opts,
1569
0
                                               *(field.value.type.enum_def));
1570
1571
0
            field_val = GenUnionValTS(imports, struct_def, field_method,
1572
0
                                      field.value.type);
1573
0
            field_offset_decl =
1574
0
                "builder.createObjectOffset(this." + field_field + ")";
1575
0
            break;
1576
0
          }
1577
1578
0
          default:
1579
0
            FLATBUFFERS_ASSERT(0);
1580
0
            break;
1581
0
        }
1582
1583
        // length 0 vector is simply empty instead of null/undefined.
1584
0
        field_type += is_vector ? "" : ("|" + null_keyword_);
1585
0
      }
1586
1587
0
      if (!field_offset_decl.empty()) {
1588
0
        field_offset_decl =
1589
0
            "  const " + field_field + " = " + field_offset_decl + ";";
1590
0
      }
1591
0
      if (field_offset_val.empty()) {
1592
0
        field_offset_val = field_field;
1593
0
      }
1594
1595
0
      unpack_func += "    " + field_val;
1596
0
      unpack_to_func += "  _o." + field_field + " = " + field_val + ";";
1597
1598
      // FIXME: if field_type and field_field are identical, then
1599
      // this generates invalid typescript.
1600
0
      constructor_func += "  public " + field_field + ": " + field_type +
1601
0
                          " = " + field_default_val;
1602
1603
0
      if (!struct_def.fixed) {
1604
0
        if (!field_offset_decl.empty()) {
1605
0
          pack_func_offset_decl += field_offset_decl + "\n";
1606
0
        }
1607
1608
0
        if (has_create) {
1609
0
          pack_func_create_call += field_offset_val;
1610
0
        } else {
1611
0
          if (field.IsScalarOptional()) {
1612
0
            pack_func_create_call +=
1613
0
                "  if (" + field_offset_val + " !== " + null_keyword_ + ")\n  ";
1614
0
          }
1615
0
          pack_func_create_call += "  " + struct_name + "." +
1616
0
                                   namer_.Method("add", field) + "(builder, " +
1617
0
                                   field_offset_val + ");\n";
1618
0
        }
1619
0
      }
1620
1621
0
      if (std::next(it) != struct_def.fields.vec.end()) {
1622
0
        constructor_func += ",\n";
1623
1624
0
        if (!struct_def.fixed && has_create) {
1625
0
          pack_func_create_call += ",\n    ";
1626
0
        }
1627
1628
0
        unpack_func += ",\n";
1629
0
        unpack_to_func += "\n";
1630
0
      } else {
1631
0
        constructor_func += "\n";
1632
0
        if (!struct_def.fixed) {
1633
0
          pack_func_offset_decl += (pack_func_offset_decl.empty() ? "" : "\n");
1634
0
          pack_func_create_call += "\n  ";
1635
0
        }
1636
1637
0
        unpack_func += "\n  ";
1638
0
        unpack_to_func += "\n";
1639
0
      }
1640
0
    }
1641
1642
0
    constructor_func += "){}\n\n";
1643
1644
0
    if (has_create) {
1645
0
      pack_func_create_call += ");";
1646
0
    } else {
1647
0
      pack_func_create_call += "return " + struct_name + ".end" +
1648
0
                               GetPrefixedName(struct_def) + "(builder);";
1649
0
    }
1650
0
    obj_api_class = "\n";
1651
0
    obj_api_class += "export class ";
1652
0
    obj_api_class += GetTypeName(struct_def, /*object_api=*/true);
1653
0
    obj_api_class += " implements flatbuffers.IGeneratedObject {\n";
1654
0
    obj_api_class += constructor_func;
1655
0
    obj_api_class += pack_func_prototype + pack_func_offset_decl +
1656
0
                     pack_func_create_call + "\n}";
1657
1658
0
    obj_api_class += "\n}\n";
1659
1660
0
    unpack_func += ");\n}";
1661
0
    unpack_to_func += "}\n";
1662
1663
0
    obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func;
1664
0
  }
1665
1666
0
  static bool CanCreateFactoryMethod(const StructDef& struct_def) {
1667
    // to preserve backwards compatibility, we allow the first field to be a
1668
    // struct
1669
0
    return struct_def.fields.vec.size() < 2 ||
1670
0
           std::all_of(
1671
0
               std::begin(struct_def.fields.vec) + 1,
1672
0
               std::end(struct_def.fields.vec),
1673
0
               [](const FieldDef* f) -> bool {
1674
0
                 FLATBUFFERS_ASSERT(f != nullptr);
1675
0
                 return f->value.type.base_type != BASE_TYPE_STRUCT;
1676
0
               });
1677
0
  }
1678
1679
  // Generate an accessor struct with constructor for a flatbuffers struct.
1680
  void GenStruct(const Parser& parser, StructDef& struct_def,
1681
0
                 std::string* code_ptr, import_set& imports) {
1682
0
    if (struct_def.generated) return;
1683
0
    std::string& code = *code_ptr;
1684
1685
    // Special case for the root struct, since no one will necessarily reference
1686
    // it, we have to explicitly add it to the import list.
1687
0
    if (&struct_def == parser_.root_struct_def_) {
1688
0
      AddImport(imports, struct_def, struct_def);
1689
0
    }
1690
1691
0
    const std::string object_name = GetTypeName(struct_def);
1692
0
    const std::string object_api_name = GetTypeName(struct_def, true);
1693
1694
    // Emit constructor
1695
0
    GenDocComment(struct_def.doc_comment, code_ptr);
1696
0
    code += "export class ";
1697
0
    code += object_name;
1698
0
    if (parser.opts.generate_object_based_api) {
1699
0
      code += " implements flatbuffers.IUnpackableObject<" + object_api_name +
1700
0
              "> {\n";
1701
0
    } else {
1702
0
      code += " {\n";
1703
0
    }
1704
0
    code += "  bb: flatbuffers.ByteBuffer|" + null_keyword_ + " = " +
1705
0
            null_keyword_ + ";\n";
1706
0
    code += "  bb_pos = 0;\n";
1707
1708
    // Generate the __init method that sets the field in a pre-existing
1709
    // accessor object. This is to allow object reuse.
1710
0
    code +=
1711
0
        "  __init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
1712
0
    code += "  this.bb_pos = i;\n";
1713
0
    code += "  this.bb = bb;\n";
1714
0
    code += "  return this;\n";
1715
0
    code += "}\n\n";
1716
1717
    // Generate special accessors for the table that when used as the root of a
1718
    // FlatBuffer
1719
0
    GenerateRootAccessor(struct_def, code_ptr, code, object_name, false);
1720
0
    GenerateRootAccessor(struct_def, code_ptr, code, object_name, true);
1721
1722
    // Generate the identifier check method
1723
0
    if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
1724
0
        !parser_.file_identifier_.empty()) {
1725
0
      GenDocComment(code_ptr);
1726
0
      code +=
1727
0
          "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
1728
0
          "{\n";
1729
0
      code += "  return bb.__has_identifier('" + parser_.file_identifier_;
1730
0
      code += "');\n}\n\n";
1731
0
    }
1732
1733
    // Emit field accessors
1734
0
    for (auto it = struct_def.fields.vec.begin();
1735
0
         it != struct_def.fields.vec.end(); ++it) {
1736
0
      auto& field = **it;
1737
0
      if (field.deprecated) continue;
1738
0
      std::string offset_prefix = "";
1739
1740
0
      if (field.value.type.base_type == BASE_TYPE_ARRAY) {
1741
0
        offset_prefix = "    return ";
1742
0
      } else {
1743
0
        offset_prefix = "  const offset = " + GenBBAccess() +
1744
0
                        ".__offset(this.bb_pos, " +
1745
0
                        NumToString(field.value.offset) + ");\n";
1746
0
        offset_prefix += "  return ";
1747
0
      }
1748
1749
      // Emit a scalar field
1750
0
      const auto is_string = IsString(field.value.type);
1751
0
      if (IsScalar(field.value.type.base_type) || is_string) {
1752
0
        const auto has_null_default =
1753
0
            !field.IsRequired() && !HasDefaultValue(field);
1754
1755
0
        GenDocComment(field.doc_comment, code_ptr);
1756
0
        std::string prefix = namer_.Method(field) + "(";
1757
0
        if (is_string) {
1758
0
          code += prefix + "):" + (has_null_default ? "string|" + null_keyword_ : "string") + "\n";
1759
0
          code +=
1760
0
              prefix + "optionalEncoding:flatbuffers.Encoding" + "):" +
1761
0
              GenTypeName(imports, struct_def, field.value.type, false, has_null_default) +
1762
0
              "\n";
1763
0
          code += prefix + "optionalEncoding?:any";
1764
0
        } else {
1765
0
          code += prefix;
1766
0
        }
1767
0
        if (field.value.type.enum_def) {
1768
0
          code += "):" +
1769
0
                  GenTypeName(imports, struct_def, field.value.type, false,
1770
0
                              field.IsOptional()) +
1771
0
                  " {\n";
1772
0
        } else {
1773
0
          code += "):" +
1774
0
                  GenTypeName(imports, struct_def, field.value.type, false,
1775
0
                              has_null_default) +
1776
0
                  " {\n";
1777
0
        }
1778
1779
0
        if (struct_def.fixed) {
1780
0
          code +=
1781
0
              "  return " +
1782
0
              GenGetter(field.value.type,
1783
0
                        "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") +
1784
0
              ";\n";
1785
0
        } else {
1786
0
          std::string index = "this.bb_pos + offset";
1787
0
          if (is_string) {
1788
0
            index += ", optionalEncoding";
1789
0
          }
1790
0
          if (field.IsRequired()) {
1791
0
            code +=
1792
0
                offset_prefix + GenGetter(field.value.type, "(" + index + ")");
1793
0
            ;
1794
0
          } else {
1795
0
            code += offset_prefix + "offset ? " +
1796
0
                    GenGetter(field.value.type, "(" + index + ")");
1797
0
          }
1798
0
          if (field.value.type.base_type != BASE_TYPE_ARRAY &&
1799
0
              !field.IsRequired()) {
1800
0
            code += " : " + GenDefaultValue(field, imports);
1801
0
          }
1802
0
          code += ";\n";
1803
0
        }
1804
0
      }
1805
1806
      // Emit an object field
1807
0
      else {
1808
0
        switch (field.value.type.base_type) {
1809
0
          case BASE_TYPE_STRUCT: {
1810
0
            const auto type =
1811
0
                AddImport(imports, struct_def, *field.value.type.struct_def)
1812
0
                    .name;
1813
0
            GenDocComment(field.doc_comment, code_ptr);
1814
0
            code += namer_.Method(field);
1815
0
            code +=
1816
0
                "(obj?:" + type + "):" + type + "|" + null_keyword_ + " {\n";
1817
1818
0
            if (struct_def.fixed) {
1819
0
              code += "  return (obj || " + GenerateNewExpression(type);
1820
0
              code += ").__init(this.bb_pos";
1821
0
              code +=
1822
0
                  MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
1823
0
            } else {
1824
0
              code += offset_prefix + "offset ? (obj || " +
1825
0
                      GenerateNewExpression(type) + ").__init(";
1826
0
              code += field.value.type.struct_def->fixed
1827
0
                          ? "this.bb_pos + offset"
1828
0
                          : GenBBAccess() + ".__indirect(this.bb_pos + offset)";
1829
0
              code += ", " + GenBBAccess() + ") : " + null_keyword_ + ";\n";
1830
0
            }
1831
1832
0
            break;
1833
0
          }
1834
1835
0
          case BASE_TYPE_ARRAY: {
1836
0
            auto vectortype = field.value.type.VectorType();
1837
0
            auto vectortypename =
1838
0
                GenTypeName(imports, struct_def, vectortype, false);
1839
0
            auto inline_size = InlineSize(vectortype);
1840
0
            auto index = "this.bb_pos + " + NumToString(field.value.offset) +
1841
0
                         " + index" + MaybeScale(inline_size);
1842
0
            std::string ret_type;
1843
0
            bool is_union = false;
1844
0
            switch (vectortype.base_type) {
1845
0
              case BASE_TYPE_STRUCT:
1846
0
                ret_type = vectortypename;
1847
0
                break;
1848
0
              case BASE_TYPE_STRING:
1849
0
                ret_type = vectortypename;
1850
0
                break;
1851
0
              case BASE_TYPE_UNION:
1852
0
                ret_type = "?flatbuffers.Table";
1853
0
                is_union = true;
1854
0
                break;
1855
0
              default:
1856
0
                ret_type = vectortypename;
1857
0
            }
1858
0
            GenDocComment(field.doc_comment, code_ptr);
1859
0
            std::string prefix = namer_.Method(field);
1860
            // TODO: make it work without any
1861
            // if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
1862
0
            if (is_union) {
1863
0
              prefix += "";
1864
0
            }
1865
0
            prefix += "(index: number";
1866
0
            if (is_union) {
1867
0
              const auto union_type =
1868
0
                  GenUnionGenericTypeTS(*(field.value.type.enum_def));
1869
1870
0
              vectortypename = union_type;
1871
0
              code += prefix + ", obj:" + union_type;
1872
0
            } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
1873
0
              code += prefix + ", obj?:" + vectortypename;
1874
0
            } else if (IsString(vectortype)) {
1875
0
              code += prefix + "):string\n";
1876
0
              code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
1877
0
                      "):" + vectortypename + "\n";
1878
0
              code += prefix + ",optionalEncoding?:any";
1879
0
            } else {
1880
0
              code += prefix;
1881
0
            }
1882
0
            code += "):" + vectortypename + "|" + null_keyword_ + " {\n";
1883
1884
0
            if (vectortype.base_type == BASE_TYPE_STRUCT) {
1885
0
              code += offset_prefix + "(obj || " +
1886
0
                      GenerateNewExpression(vectortypename);
1887
0
              code += ").__init(";
1888
0
              code += vectortype.struct_def->fixed
1889
0
                          ? index
1890
0
                          : GenBBAccess() + ".__indirect(" + index + ")";
1891
0
              code += ", " + GenBBAccess() + ")";
1892
0
            } else {
1893
0
              if (is_union) {
1894
0
                index = "obj, " + index;
1895
0
              } else if (IsString(vectortype)) {
1896
0
                index += ", optionalEncoding";
1897
0
              }
1898
0
              code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
1899
0
            }
1900
1901
0
            switch (field.value.type.base_type) {
1902
0
              case BASE_TYPE_ARRAY: {
1903
0
                break;
1904
0
              }
1905
0
              case BASE_TYPE_BOOL: {
1906
0
                code += " : false";
1907
0
                break;
1908
0
              }
1909
0
              case BASE_TYPE_LONG:
1910
0
              case BASE_TYPE_ULONG: {
1911
0
                code += " : BigInt(0)";
1912
0
                break;
1913
0
              }
1914
0
              default: {
1915
0
                if (IsScalar(field.value.type.element)) {
1916
0
                  if (field.value.type.enum_def) {
1917
0
                    code += field.value.constant;
1918
0
                  } else {
1919
0
                    code += " : 0";
1920
0
                  }
1921
0
                } else {
1922
0
                  code += ": " + null_keyword_;
1923
0
                }
1924
0
                break;
1925
0
              }
1926
0
            }
1927
0
            code += ";\n";
1928
0
            break;
1929
0
          }
1930
1931
0
          case BASE_TYPE_VECTOR: {
1932
0
            auto vectortype = field.value.type.VectorType();
1933
0
            auto vectortypename =
1934
0
                GenTypeName(imports, struct_def, vectortype, false);
1935
0
            auto type = GetUnderlyingVectorType(vectortype);
1936
0
            auto inline_size = InlineSize(type);
1937
0
            auto index = GenBBAccess() +
1938
0
                         ".__vector(this.bb_pos + offset) + index" +
1939
0
                         MaybeScale(inline_size);
1940
0
            std::string ret_type;
1941
0
            bool is_union = false;
1942
0
            switch (vectortype.base_type) {
1943
0
              case BASE_TYPE_STRUCT:
1944
0
                ret_type = vectortypename;
1945
0
                break;
1946
0
              case BASE_TYPE_STRING:
1947
0
                ret_type = vectortypename;
1948
0
                break;
1949
0
              case BASE_TYPE_UNION:
1950
0
                ret_type = "?flatbuffers.Table";
1951
0
                is_union = true;
1952
0
                break;
1953
0
              default:
1954
0
                ret_type = vectortypename;
1955
0
            }
1956
0
            GenDocComment(field.doc_comment, code_ptr);
1957
0
            std::string prefix = namer_.Method(field);
1958
            // TODO: make it work without any
1959
            // if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
1960
0
            if (is_union) {
1961
0
              prefix += "";
1962
0
            }
1963
0
            prefix += "(index: number";
1964
0
            if (is_union) {
1965
0
              const auto union_type =
1966
0
                  GenUnionGenericTypeTS(*(field.value.type.enum_def));
1967
1968
0
              vectortypename = union_type;
1969
0
              code += prefix + ", obj:" + union_type;
1970
0
            } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
1971
0
              code += prefix + ", obj?:" + vectortypename;
1972
0
            } else if (IsString(vectortype)) {
1973
0
              code += prefix + "):string\n";
1974
0
              code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
1975
0
                      "):" + vectortypename + "\n";
1976
0
              code += prefix + ",optionalEncoding?:any";
1977
0
            } else {
1978
0
              code += prefix;
1979
0
            }
1980
0
            code += "):" + vectortypename + "|" + null_keyword_ + " {\n";
1981
1982
0
            if (vectortype.base_type == BASE_TYPE_STRUCT) {
1983
0
              code += offset_prefix + "offset ? (obj || " +
1984
0
                      GenerateNewExpression(vectortypename);
1985
0
              code += ").__init(";
1986
0
              code += vectortype.struct_def->fixed
1987
0
                          ? index
1988
0
                          : GenBBAccess() + ".__indirect(" + index + ")";
1989
0
              code += ", " + GenBBAccess() + ")";
1990
0
            } else {
1991
0
              if (is_union) {
1992
0
                index = "obj, " + index;
1993
0
              } else if (IsString(vectortype)) {
1994
0
                index += ", optionalEncoding";
1995
0
              }
1996
0
              code += offset_prefix + "offset ? " +
1997
0
                      GenGetter(vectortype, "(" + index + ")");
1998
0
            }
1999
0
            code += " : ";
2000
0
            if (field.value.type.element == BASE_TYPE_BOOL) {
2001
0
              code += "false";
2002
0
            } else if (field.value.type.element == BASE_TYPE_LONG ||
2003
0
                       field.value.type.element == BASE_TYPE_ULONG) {
2004
0
              code += "BigInt(0)";
2005
0
            } else if (IsScalar(field.value.type.element)) {
2006
0
              if (field.value.type.enum_def) {
2007
0
                code += null_keyword_;
2008
0
              } else {
2009
0
                code += "0";
2010
0
              }
2011
0
            } else {
2012
0
              code += null_keyword_;
2013
0
            }
2014
0
            code += ";\n";
2015
0
            break;
2016
0
          }
2017
2018
0
          case BASE_TYPE_UNION: {
2019
0
            GenDocComment(field.doc_comment, code_ptr);
2020
0
            code += namer_.Method(field);
2021
2022
0
            const auto& union_enum = *(field.value.type.enum_def);
2023
0
            const auto union_type = GenUnionGenericTypeTS(union_enum);
2024
0
            code += "<T extends flatbuffers.Table>(obj:" + union_type +
2025
0
                    "):" + union_type + "|" + null_keyword_ +
2026
0
                    " "
2027
0
                    "{\n";
2028
2029
0
            code += offset_prefix + "offset ? " +
2030
0
                    GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
2031
0
                    " : " + null_keyword_ + ";\n";
2032
0
            break;
2033
0
          }
2034
0
          default:
2035
0
            FLATBUFFERS_ASSERT(0);
2036
0
        }
2037
0
      }
2038
0
      code += "}\n\n";
2039
2040
      // Adds the mutable scalar value to the output
2041
0
      if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer &&
2042
0
          !IsUnion(field.value.type)) {
2043
0
        std::string type =
2044
0
            GenTypeName(imports, struct_def, field.value.type, true);
2045
2046
0
        code += namer_.LegacyTsMutateMethod(field) + "(value:" + type +
2047
0
                "):boolean {\n";
2048
2049
0
        const std::string write_method =
2050
0
            "." + namer_.Method("write", GenType(field.value.type));
2051
2052
0
        if (struct_def.fixed) {
2053
0
          code += "  " + GenBBAccess() + write_method + "(this.bb_pos + " +
2054
0
                  NumToString(field.value.offset) + ", ";
2055
0
        } else {
2056
0
          code += "  const offset = " + GenBBAccess() +
2057
0
                  ".__offset(this.bb_pos, " + NumToString(field.value.offset) +
2058
0
                  ");\n\n";
2059
0
          code += "  if (offset === 0) {\n";
2060
0
          code += "    return false;\n";
2061
0
          code += "  }\n\n";
2062
2063
0
          code +=
2064
0
              "  " + GenBBAccess() + write_method + "(this.bb_pos + offset, ";
2065
0
        }
2066
2067
        // special case for bools, which are treated as uint8
2068
0
        if (field.value.type.base_type == BASE_TYPE_BOOL) {
2069
0
          code += "+";
2070
0
        }
2071
2072
0
        code += "value);\n";
2073
0
        code += "  return true;\n";
2074
0
        code += "}\n\n";
2075
0
      }
2076
2077
      // Emit vector helpers
2078
0
      if (IsVector(field.value.type)) {
2079
        // Emit a length helper
2080
0
        GenDocComment(code_ptr);
2081
0
        code += namer_.Method(field, "Length");
2082
0
        code += "():number {\n" + offset_prefix + "offset ? ";
2083
2084
0
        code +=
2085
0
            GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n}\n\n";
2086
2087
        // For scalar types, emit a typed array helper
2088
0
        auto vectorType = field.value.type.VectorType();
2089
0
        if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
2090
0
          GenDocComment(code_ptr);
2091
2092
0
          code += namer_.Method(field, "Array");
2093
2094
0
          std::string return_type =
2095
0
              (field.IsRequired() || HasDefaultValue(field))
2096
0
                  ? "Array"
2097
0
                  : ("Array|" + null_keyword_);
2098
0
          if (field.IsRequired()) {
2099
0
            code += "():" + GenType(vectorType) + return_type + " {\n" +
2100
0
                    offset_prefix + "new " + GenType(vectorType) + "Array(" +
2101
0
                    GenBBAccess() + ".bytes().buffer, " + GenBBAccess() +
2102
0
                    ".bytes().byteOffset + " + GenBBAccess() +
2103
0
                    ".__vector(this.bb_pos + offset), " + GenBBAccess() +
2104
0
                    ".__vector_len(this.bb_pos + offset));\n}\n\n";
2105
0
          } else {
2106
0
            std::string value = HasDefaultValue(field)
2107
0
                                    ? "new " + GenType(vectorType) + "Array()"
2108
0
                                    : "null";
2109
0
            code += "():" + GenType(vectorType) + return_type + " {\n" +
2110
0
                    offset_prefix + "offset ? new " + GenType(vectorType) +
2111
0
                    "Array(" + GenBBAccess() + ".bytes().buffer, " +
2112
0
                    GenBBAccess() + ".bytes().byteOffset + " + GenBBAccess() +
2113
0
                    ".__vector(this.bb_pos + offset), " + GenBBAccess() +
2114
0
                    ".__vector_len(this.bb_pos + offset)) : " + value +
2115
0
                    ";\n}\n\n";
2116
0
          }
2117
0
        }
2118
0
      }
2119
0
    }
2120
2121
    // Emit the fully qualified name
2122
0
    if (parser_.opts.generate_name_strings) {
2123
0
      const std::string fullyQualifiedName =
2124
0
          struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
2125
2126
0
      GenDocComment(code_ptr);
2127
0
      code += "static getFullyQualifiedName(): \"";
2128
0
      code += fullyQualifiedName;
2129
0
      code += "\" {\n";
2130
0
      code += "  return '" + fullyQualifiedName + "';\n";
2131
0
      code += "}\n\n";
2132
0
    }
2133
2134
    // Emit the size of the struct.
2135
0
    if (struct_def.fixed) {
2136
0
      GenDocComment(code_ptr);
2137
0
      code += "static sizeOf():number {\n";
2138
0
      code += "  return " + NumToString(struct_def.bytesize) + ";\n";
2139
0
      code += "}\n\n";
2140
0
    }
2141
2142
    // Emit a factory constructor
2143
0
    if (struct_def.fixed) {
2144
0
      std::string arguments;
2145
0
      GenStructArgs(imports, struct_def, struct_def, &arguments, "");
2146
0
      GenDocComment(code_ptr);
2147
2148
0
      code += "static create" + GetPrefixedName(struct_def) +
2149
0
              "(builder:flatbuffers.Builder";
2150
0
      code += arguments + "):flatbuffers.Offset {\n";
2151
2152
0
      GenStructBody(struct_def, &code, "");
2153
0
      code += "  return builder.offset();\n}\n\n";
2154
0
    } else {
2155
      // Generate a method to start building a new object
2156
0
      GenDocComment(code_ptr);
2157
2158
0
      code += "static start" + GetPrefixedName(struct_def) +
2159
0
              "(builder:flatbuffers.Builder) {\n";
2160
2161
0
      code += "  builder.startObject(" +
2162
0
              NumToString(struct_def.fields.vec.size()) + ");\n";
2163
0
      code += "}\n\n";
2164
2165
      // Generate a set of static methods that allow table construction
2166
0
      for (auto it = struct_def.fields.vec.begin();
2167
0
           it != struct_def.fields.vec.end(); ++it) {
2168
0
        auto& field = **it;
2169
0
        if (field.deprecated) continue;
2170
0
        const auto argname = GetArgName(field);
2171
2172
        // Generate the field insertion method
2173
0
        GenDocComment(code_ptr);
2174
0
        code += "static " + namer_.Method("add", field);
2175
0
        code += "(builder:flatbuffers.Builder, " + argname + ":" +
2176
0
                GetArgType(imports, struct_def, field, false) + ") {\n";
2177
0
        code += "  builder.addField" + GenWriteMethod(field.value.type) + "(";
2178
0
        code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
2179
0
        if (field.value.type.base_type == BASE_TYPE_BOOL) {
2180
0
          code += "+";
2181
0
        }
2182
0
        code += argname + ", ";
2183
0
        if (!IsScalar(field.value.type.base_type)) {
2184
0
          code += "0";
2185
0
        } else if (HasNullDefault(field)) {
2186
0
          code += null_keyword_;
2187
0
        } else {
2188
0
          if (field.value.type.base_type == BASE_TYPE_BOOL) {
2189
0
            code += "+";
2190
0
          }
2191
0
          code += GenDefaultValue(field, imports);
2192
0
        }
2193
0
        code += ");\n}\n\n";
2194
2195
0
        if (IsVector(field.value.type)) {
2196
0
          auto vector_type = field.value.type.VectorType();
2197
0
          auto type = GetUnderlyingVectorType(vector_type);
2198
0
          auto alignment = InlineAlignment(type);
2199
0
          auto elem_size = InlineSize(type);
2200
2201
          // Generate a method to create a vector from a JavaScript array
2202
0
          if (!IsStruct(vector_type)) {
2203
0
            GenDocComment(code_ptr);
2204
2205
0
            const std::string sig_begin =
2206
0
                "static " + namer_.Method("create", field, "Vector") +
2207
0
                "(builder:flatbuffers.Builder, data:";
2208
0
            const std::string sig_end = "):flatbuffers.Offset";
2209
0
            std::string type =
2210
0
                GenTypeName(imports, struct_def, vector_type, true) + "[]";
2211
0
            if (type == "number[]") {
2212
0
              const auto& array_type = GenType(vector_type);
2213
              // the old type should be deprecated in the future
2214
0
              std::string type_old = "number[]|Uint8Array";
2215
0
              std::string type_new = "number[]|" + array_type + "Array";
2216
0
              if (type_old == type_new) {
2217
0
                type = type_new;
2218
0
              } else {
2219
                // add function overloads
2220
0
                code += sig_begin + type_new + sig_end + ";\n";
2221
0
                code +=
2222
0
                    "/**\n * @deprecated This Uint8Array overload will "
2223
0
                    "be removed in the future.\n */\n";
2224
0
                code += sig_begin + type_old + sig_end + ";\n";
2225
0
                type = type_new + "|Uint8Array";
2226
0
              }
2227
0
            }
2228
0
            code += sig_begin + type + sig_end + " {\n";
2229
0
            code += "  builder.startVector(" + NumToString(elem_size);
2230
0
            code += ", data.length, " + NumToString(alignment) + ");\n";
2231
0
            code += "  for (let i = data.length - 1; i >= 0; i--) {\n";
2232
0
            code += "    builder.add" + GenWriteMethod(vector_type) + "(";
2233
0
            if (vector_type.base_type == BASE_TYPE_BOOL) {
2234
0
              code += "+";
2235
0
            }
2236
0
            code += "data[i]!);\n";
2237
0
            code += "  }\n";
2238
0
            code += "  return builder.endVector();\n";
2239
0
            code += "}\n\n";
2240
0
          }
2241
2242
          // Generate a method to start a vector, data to be added manually
2243
          // after
2244
0
          GenDocComment(code_ptr);
2245
2246
0
          code += "static ";
2247
0
          code += namer_.Method("start", field, "Vector");
2248
0
          code += "(builder:flatbuffers.Builder, numElems:number) {\n";
2249
0
          code += "  builder.startVector(" + NumToString(elem_size);
2250
0
          code += ", numElems, " + NumToString(alignment) + ");\n";
2251
0
          code += "}\n\n";
2252
0
        }
2253
0
      }
2254
2255
      // Generate a method to stop building a new object
2256
0
      GenDocComment(code_ptr);
2257
2258
0
      code += "static end" + GetPrefixedName(struct_def);
2259
0
      code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
2260
2261
0
      code += "  const offset = builder.endObject();\n";
2262
0
      for (auto it = struct_def.fields.vec.begin();
2263
0
           it != struct_def.fields.vec.end(); ++it) {
2264
0
        auto& field = **it;
2265
0
        if (!field.deprecated && field.IsRequired()) {
2266
0
          code += "  builder.requiredField(offset, ";
2267
0
          code += NumToString(field.value.offset);
2268
0
          code += ") // " + field.name + "\n";
2269
0
        }
2270
0
      }
2271
0
      code += "  return offset;\n";
2272
0
      code += "}\n\n";
2273
2274
      // Generate the methods to complete buffer construction
2275
0
      GenerateFinisher(struct_def, code_ptr, code, false);
2276
0
      GenerateFinisher(struct_def, code_ptr, code, true);
2277
2278
      // Generate a convenient CreateX function
2279
0
      if (CanCreateFactoryMethod(struct_def)) {
2280
0
        code += "static create" + GetPrefixedName(struct_def);
2281
0
        code += "(builder:flatbuffers.Builder";
2282
0
        for (auto it = struct_def.fields.vec.begin();
2283
0
             it != struct_def.fields.vec.end(); ++it) {
2284
0
          const auto& field = **it;
2285
0
          if (field.deprecated) continue;
2286
0
          code += ", " + GetArgName(field) + ":" +
2287
0
                  GetArgType(imports, struct_def, field, true);
2288
0
        }
2289
2290
0
        code += "):flatbuffers.Offset {\n";
2291
0
        code += "  " + object_name + ".start" + GetPrefixedName(struct_def) +
2292
0
                "(builder);\n";
2293
2294
0
        std::string methodPrefix = object_name;
2295
0
        for (auto it = struct_def.fields.vec.begin();
2296
0
             it != struct_def.fields.vec.end(); ++it) {
2297
0
          const auto& field = **it;
2298
0
          if (field.deprecated) continue;
2299
2300
0
          const auto arg_name = GetArgName(field);
2301
2302
0
          if (field.IsScalarOptional()) {
2303
0
            code += "  if (" + arg_name + " !== " + null_keyword_ + ")\n  ";
2304
0
          }
2305
2306
0
          code += "  " + methodPrefix + "." + namer_.Method("add", field) + "(";
2307
0
          code += "builder, " + arg_name + ");\n";
2308
0
        }
2309
2310
0
        code += "  return " + methodPrefix + ".end" +
2311
0
                GetPrefixedName(struct_def) + "(builder);\n";
2312
0
        code += "}\n";
2313
0
      }
2314
0
    }
2315
2316
0
    if (!struct_def.fixed && parser_.services_.vec.size() != 0) {
2317
0
      auto name = GetPrefixedName(struct_def, "");
2318
0
      code += "\n";
2319
0
      code += "serialize():Uint8Array {\n";
2320
0
      code += "  return this.bb!.bytes();\n";
2321
0
      code += "}\n";
2322
2323
0
      code += "\n";
2324
0
      code += "static deserialize(buffer: Uint8Array):" +
2325
0
              namer_.EscapeKeyword(name) + " {\n";
2326
0
      code += "  return " + AddImport(imports, struct_def, struct_def).name +
2327
0
              ".getRootAs" + name + "(new flatbuffers.ByteBuffer(buffer))\n";
2328
0
      code += "}\n";
2329
0
    }
2330
2331
0
    if (parser_.opts.generate_object_based_api) {
2332
0
      std::string obj_api_class;
2333
0
      std::string obj_api_unpack_func;
2334
0
      GenObjApi(parser_, struct_def, obj_api_unpack_func, obj_api_class,
2335
0
                imports);
2336
2337
0
      code += obj_api_unpack_func + "}\n" + obj_api_class;
2338
0
    } else {
2339
0
      code += "}\n";
2340
0
    }
2341
0
  }
2342
2343
0
  bool HasNullDefault(const FieldDef& field) {
2344
0
    return field.IsOptional() && field.value.constant == "null";
2345
0
  }
2346
2347
0
  static bool HasDefaultValue(const FieldDef& field) {
2348
0
    switch (field.value.type.base_type) {
2349
      // These types can't have defaults
2350
0
      case BASE_TYPE_UNION:
2351
0
      case BASE_TYPE_STRUCT: {
2352
0
        return false;
2353
0
      }
2354
2355
      // Arrays always have a default (empty array)
2356
0
      case BASE_TYPE_ARRAY:
2357
0
        return true;
2358
2359
      // The only supported default for vectors is []
2360
0
      case BASE_TYPE_VECTOR:
2361
0
        return field.value.constant == "[]";
2362
2363
      // Even strings are presumed to be null-default if the default value is
2364
      // "0", this is intended behavior.
2365
0
      case BASE_TYPE_STRING: {
2366
0
        return field.value.constant != "0" && field.value.constant != "null";
2367
0
      }
2368
2369
0
      default: {
2370
0
        return field.value.constant != "null";
2371
0
      }
2372
0
    }
2373
0
  }
2374
2375
  std::string GetArgType(import_set& imports, const Definition& owner,
2376
0
                         const FieldDef& field, bool allowNull) {
2377
0
    return GenTypeName(imports, owner, field.value.type, true,
2378
0
                       allowNull && field.IsOptional());
2379
0
  }
2380
2381
0
  std::string GetArgName(const FieldDef& field) {
2382
0
    auto argname = namer_.Variable(field);
2383
0
    if (!IsScalar(field.value.type.base_type)) {
2384
0
      argname += "Offset";
2385
0
    }
2386
0
    return argname;
2387
0
  }
2388
2389
  std::string GetPrefixedName(const StructDef& struct_def,
2390
0
                              const char* prefix = "") {
2391
0
    return prefix + struct_def.name;
2392
0
  }
2393
};  // namespace ts
2394
}  // namespace ts
2395
2396
static bool GenerateTS(const Parser& parser, const std::string& path,
2397
0
                       const std::string& file_name) {
2398
0
  ts::TsGenerator generator(parser, path, file_name);
2399
0
  return generator.generate();
2400
0
}
2401
2402
static std::string TSMakeRule(const Parser& parser, const std::string& path,
2403
0
                              const std::string& file_name) {
2404
0
  std::string filebase =
2405
0
      flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
2406
0
  ts::TsGenerator generator(parser, path, file_name);
2407
0
  std::string make_rule =
2408
0
      generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
2409
2410
0
  auto included_files = parser.GetIncludedFilesRecursive(file_name);
2411
0
  for (auto it = included_files.begin(); it != included_files.end(); ++it) {
2412
0
    make_rule += " " + *it;
2413
0
  }
2414
0
  return make_rule;
2415
0
}
2416
2417
namespace {
2418
2419
class TsCodeGenerator : public CodeGenerator {
2420
 public:
2421
  Status GenerateCode(const Parser& parser, const std::string& path,
2422
0
                      const std::string& filename) override {
2423
0
    if (!GenerateTS(parser, path, filename)) {
2424
0
      return Status::ERROR;
2425
0
    }
2426
0
    return Status::OK;
2427
0
  }
2428
2429
0
  Status GenerateCode(const uint8_t*, int64_t, const CodeGenOptions&) override {
2430
0
    return Status::NOT_IMPLEMENTED;
2431
0
  }
2432
2433
  Status GenerateMakeRule(const Parser& parser, const std::string& path,
2434
                          const std::string& filename,
2435
0
                          std::string& output) override {
2436
0
    output = TSMakeRule(parser, path, filename);
2437
0
    return Status::OK;
2438
0
  }
2439
2440
  Status GenerateGrpcCode(const Parser& parser, const std::string& path,
2441
0
                          const std::string& filename) override {
2442
0
    if (!GenerateTSGRPC(parser, path, filename)) {
2443
0
      return Status::ERROR;
2444
0
    }
2445
0
    return Status::OK;
2446
0
  }
2447
2448
  Status GenerateRootFile(const Parser& parser,
2449
0
                          const std::string& path) override {
2450
0
    (void)parser;
2451
0
    (void)path;
2452
0
    return Status::NOT_IMPLEMENTED;
2453
0
  }
2454
0
  bool IsSchemaOnly() const override { return true; }
2455
2456
0
  bool SupportsBfbsGeneration() const override { return false; }
2457
0
  bool SupportsRootFileGeneration() const override { return false; }
2458
2459
0
  IDLOptions::Language Language() const override { return IDLOptions::kTs; }
2460
2461
0
  std::string LanguageName() const override { return "TS"; }
2462
};
2463
}  // namespace
2464
2465
0
std::unique_ptr<CodeGenerator> NewTsCodeGenerator() {
2466
0
  return std::unique_ptr<TsCodeGenerator>(new TsCodeGenerator());
2467
0
}
2468
2469
}  // namespace flatbuffers