Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 87 additions & 27 deletions src/idl_gen_ts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,16 @@ class TsGenerator : public BaseGenerator {
case BASE_TYPE_BOOL:
return value.constant == "0" ? "false" : "true";

case BASE_TYPE_STRING:
case BASE_TYPE_STRING: {
// NOTE: Strings without a default value are parsed as "0" by
// the parser, so therefore we have to treat "0" as a null-signifying
// value.
if (value.constant == "0" || value.constant == "null") {
return "null";
} else {
return "\"" + value.constant + "\"";
}
}
case BASE_TYPE_UNION:
case BASE_TYPE_STRUCT: {
return null_keyword_;
Expand Down Expand Up @@ -1334,10 +1343,9 @@ class TsGenerator : public BaseGenerator {
// Emit a scalar field
const auto is_string = IsString(field.value.type);
if (IsScalar(field.value.type.base_type) || is_string) {
const auto has_null_default = is_string || HasNullDefault(field);

field_type += GenTypeName(imports, field, field.value.type, false,
has_null_default);
field_type +=
GenTypeName(imports, field, field.value.type, false,
!HasDefaultValue(field) || HasNullDefault(field));
field_val = "this." + namer_.Method(field) + "()";

if (field.value.type.base_type != BASE_TYPE_STRING) {
Expand Down Expand Up @@ -1731,21 +1739,22 @@ class TsGenerator : public BaseGenerator {
offset_prefix = " const offset = " + GenBBAccess() +
".__offset(this.bb_pos, " +
NumToString(field.value.offset) + ");\n";
offset_prefix += " return offset ? ";
offset_prefix += " return ";
}

// Emit a scalar field
const auto is_string = IsString(field.value.type);
if (IsScalar(field.value.type.base_type) || is_string) {
const auto has_null_default = is_string || HasNullDefault(field);
const auto has_null_default =
!field.IsRequired() && !HasDefaultValue(field);

GenDocComment(field.doc_comment, code_ptr);
std::string prefix = namer_.Method(field) + "(";
if (is_string) {
code += prefix + "):string|" + null_keyword_ + "\n";
code += prefix + "):" + (has_null_default ? "string|" + null_keyword_ : "string") + "\n";
code +=
prefix + "optionalEncoding:flatbuffers.Encoding" + "):" +
GenTypeName(imports, struct_def, field.value.type, false, true) +
GenTypeName(imports, struct_def, field.value.type, false, has_null_default) +
"\n";
code += prefix + "optionalEncoding?:any";
} else {
Expand Down Expand Up @@ -1774,9 +1783,16 @@ class TsGenerator : public BaseGenerator {
if (is_string) {
index += ", optionalEncoding";
}
code +=
offset_prefix + GenGetter(field.value.type, "(" + index + ")");
if (field.value.type.base_type != BASE_TYPE_ARRAY) {
if (field.IsRequired()) {
code +=
offset_prefix + GenGetter(field.value.type, "(" + index + ")");
;
} else {
code += offset_prefix + "offset ? " +
GenGetter(field.value.type, "(" + index + ")");
}
if (field.value.type.base_type != BASE_TYPE_ARRAY &&
!field.IsRequired()) {
code += " : " + GenDefaultValue(field, imports);
}
code += ";\n";
Expand All @@ -1801,8 +1817,8 @@ class TsGenerator : public BaseGenerator {
code +=
MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
} else {
code += offset_prefix + "(obj || " + GenerateNewExpression(type) +
").__init(";
code += offset_prefix + "offset ? (obj || " +
GenerateNewExpression(type) + ").__init(";
code += field.value.type.struct_def->fixed
? "this.bb_pos + offset"
: GenBBAccess() + ".__indirect(this.bb_pos + offset)";
Expand Down Expand Up @@ -1960,7 +1976,7 @@ class TsGenerator : public BaseGenerator {
code += "):" + vectortypename + "|" + null_keyword_ + " {\n";

if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += offset_prefix + "(obj || " +
code += offset_prefix + "offset ? (obj || " +
GenerateNewExpression(vectortypename);
code += ").__init(";
code += vectortype.struct_def->fixed
Expand All @@ -1973,7 +1989,8 @@ class TsGenerator : public BaseGenerator {
} else if (IsString(vectortype)) {
index += ", optionalEncoding";
}
code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
code += offset_prefix + "offset ? " +
GenGetter(vectortype, "(" + index + ")");
}
code += " : ";
if (field.value.type.element == BASE_TYPE_BOOL) {
Expand Down Expand Up @@ -2005,7 +2022,7 @@ class TsGenerator : public BaseGenerator {
" "
"{\n";

code += offset_prefix +
code += offset_prefix + "offset ? " +
GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
" : " + null_keyword_ + ";\n";
break;
Expand Down Expand Up @@ -2058,7 +2075,7 @@ class TsGenerator : public BaseGenerator {
// Emit a length helper
GenDocComment(code_ptr);
code += namer_.Method(field, "Length");
code += "():number {\n" + offset_prefix;
code += "():number {\n" + offset_prefix + "offset ? ";

code +=
GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n}\n\n";
Expand All @@ -2069,15 +2086,30 @@ class TsGenerator : public BaseGenerator {
GenDocComment(code_ptr);

code += namer_.Method(field, "Array");
code += "():" + GenType(vectorType) + "Array|" + null_keyword_ +
" {\n" + offset_prefix;

code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
".bytes().buffer, " + GenBBAccess() +
".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset)) : " + null_keyword_ +
";\n}\n\n";

std::string return_type =
(field.IsRequired() || HasDefaultValue(field))
? "Array"
: ("Array|" + null_keyword_);
if (field.IsRequired()) {
code += "():" + GenType(vectorType) + return_type + " {\n" +
offset_prefix + "new " + GenType(vectorType) + "Array(" +
GenBBAccess() + ".bytes().buffer, " + GenBBAccess() +
".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset));\n}\n\n";
} else {
std::string value = HasDefaultValue(field)
? "new " + GenType(vectorType) + "Array()"
: "null";
code += "():" + GenType(vectorType) + return_type + " {\n" +
offset_prefix + "offset ? new " + GenType(vectorType) +
"Array(" + GenBBAccess() + ".bytes().buffer, " +
GenBBAccess() + ".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset)) : " + value +
";\n}\n\n";
}
}
}
}
Expand Down Expand Up @@ -2308,6 +2340,34 @@ class TsGenerator : public BaseGenerator {
return field.IsOptional() && field.value.constant == "null";
}

static bool HasDefaultValue(const FieldDef& field) {
switch (field.value.type.base_type) {
// These types can't have defaults
case BASE_TYPE_UNION:
case BASE_TYPE_STRUCT: {
return false;
}

// Arrays always have a default (empty array)
case BASE_TYPE_ARRAY:
return true;

// The only supported default for vectors is []
case BASE_TYPE_VECTOR:
return field.value.constant == "[]";

// Even strings are presumed to be null-default if the default value is
// "0", this is intended behavior.
case BASE_TYPE_STRING: {
return field.value.constant != "0" && field.value.constant != "null";
}

default: {
return field.value.constant != "null";
}
}
}

std::string GetArgType(import_set& imports, const Definition& owner,
const FieldDef& field, bool allowNull) {
return GenTypeName(imports, owner, field.value.type, true,
Expand Down
3 changes: 2 additions & 1 deletion src/idl_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2809,7 +2809,8 @@ bool Parser::SupportsOptionalScalars() const {
bool Parser::SupportsDefaultVectorsAndStrings() const {
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim |
IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson;
IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson |
IDLOptions::kTs;
return !(opts.lang_to_generate & ~supported_langs);
}

Expand Down
23 changes: 23 additions & 0 deletions tests/even_more_defaults.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

enum ABC: int { A, B, C }

struct EvenMoreStruct {
g:[int64:2];
}

table EvenMoreDefaults {
str: EvenMoreStruct;
ints: [int] = [];
floats: [float] = [ ];
float_optional: [float];
bytes_optional: [ubyte];
floats_required: [float] (required);
empty_string: string = "";
some_string: string = "some";
zero_string: string = "0";
a_string:string (key);
required_string: string (required);
abcs: [ABC] = [];
bools: [bool] = [];
one_bool: bool = true;
}
14 changes: 14 additions & 0 deletions tests/ts/TypeScriptTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ def esbuild(input, output):
)
esbuild("monster_test.ts", "monster_test_generated.cjs")

flatc(
options=[
"--ts",
"--reflect-names",
"--gen-name-strings",
"--gen-mutable",
"--gen-object-api",
"--ts-entry-points",
"--ts-flat-files",
],
schema="../even_more_defaults.fbs",
include="../include_test",
)

flatc(
options=["--gen-object-api", "-b"],
schema="../monster_test.fbs",
Expand Down
8 changes: 4 additions & 4 deletions tests/ts/my-game/example/monster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ mutate_hp(value:number):boolean {
return true;
}

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
name():string
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array
name(optionalEncoding?:any):string|Uint8Array {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
return this.bb!.__string(this.bb_pos + offset, optionalEncoding);
}

inventory(index: number):number|null {
Expand Down
Loading