diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp index 6c6f2f0aac4..a32e03583a1 100644 --- a/src/idl_gen_js_ts.cpp +++ b/src/idl_gen_js_ts.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "flatbuffers/code_generators.h" #include "flatbuffers/flatbuffers.h" @@ -1222,6 +1223,17 @@ class JsTsGenerator : public BaseGenerator { obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func; } + bool CanCreateFactoryMethod(const StructDef &struct_def) { + // to preserve backwards compatibility, we allow the first field to be a struct + return struct_def.fields.vec.size() < 2 || std::all_of( + std::begin(struct_def.fields.vec) + 1, + std::end(struct_def.fields.vec), + [](const FieldDef *f) -> bool { + FLATBUFFERS_ASSERT(f != nullptr); + return f->value.type.base_type != BASE_TYPE_STRUCT; + }); + } + // Generate an accessor struct with constructor for a flatbuffers struct. void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr, @@ -1859,66 +1871,68 @@ class JsTsGenerator : public BaseGenerator { GenerateFinisher(struct_def, code_ptr, code, object_name, true); // Generate a convenient CreateX function - if (lang_.language == IDLOptions::kJs) { - std::string paramDoc = - GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder"); - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - const auto &field = **it; - if (field.deprecated) continue; + if (CanCreateFactoryMethod(struct_def)) { + if (lang_.language == IDLOptions::kJs) { + std::string paramDoc = + GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder"); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; + paramDoc += + GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field)); + } paramDoc += - GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field)); + GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false); + + GenDocComment(code_ptr, paramDoc); } - paramDoc += - GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false); - GenDocComment(code_ptr, paramDoc); - } + if (lang_.language == IDLOptions::kTs) { + code += "static create" + Verbose(struct_def); + code += "(builder:flatbuffers.Builder"; + } else { + code += object_name + ".create" + Verbose(struct_def); + code += " = function(builder"; + } + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; - if (lang_.language == IDLOptions::kTs) { - code += "static create" + Verbose(struct_def); - code += "(builder:flatbuffers.Builder"; - } else { - code += object_name + ".create" + Verbose(struct_def); - code += " = function(builder"; - } - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - const auto &field = **it; - if (field.deprecated) continue; + if (lang_.language == IDLOptions::kTs) { + code += ", " + GetArgName(field) + ":" + GetArgType(field); + } else { + code += ", " + GetArgName(field); + } + } if (lang_.language == IDLOptions::kTs) { - code += ", " + GetArgName(field) + ":" + GetArgType(field); + code += "):flatbuffers.Offset {\n"; + code += " " + struct_def.name + ".start" + Verbose(struct_def) + + "(builder);\n"; } else { - code += ", " + GetArgName(field); + code += ") {\n"; + code += " " + object_name + ".start" + Verbose(struct_def) + + "(builder);\n"; } - } - if (lang_.language == IDLOptions::kTs) { - code += "):flatbuffers.Offset {\n"; - code += " " + struct_def.name + ".start" + Verbose(struct_def) + - "(builder);\n"; - } else { - code += ") {\n"; - code += " " + object_name + ".start" + Verbose(struct_def) + - "(builder);\n"; - } + std::string methodPrefix = + lang_.language == IDLOptions::kTs ? struct_def.name : object_name; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; - std::string methodPrefix = - lang_.language == IDLOptions::kTs ? struct_def.name : object_name; - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - const auto &field = **it; - if (field.deprecated) continue; + code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "("; + code += "builder, " + GetArgName(field) + ");\n"; + } - code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "("; - code += "builder, " + GetArgName(field) + ");\n"; + code += " return " + methodPrefix + ".end" + Verbose(struct_def) + + "(builder);\n"; + code += "}\n"; + if (lang_.language == IDLOptions::kJs) code += "\n"; } - - code += " return " + methodPrefix + ".end" + Verbose(struct_def) + - "(builder);\n"; - code += "}\n"; - if (lang_.language == IDLOptions::kJs) code += "\n"; } if (lang_.language == IDLOptions::kTs) { diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index bc7db45b87a..7339a7340a4 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -2693,111 +2693,6 @@ MyGame.Example.Monster.finishSizePrefixedMonsterBuffer = function(builder, offse builder.finish(offset, 'MONS', true); }; -/** - * @param {flatbuffers.Builder} builder - * @param {flatbuffers.Offset} posOffset - * @param {number} mana - * @param {number} hp - * @param {flatbuffers.Offset} nameOffset - * @param {flatbuffers.Offset} inventoryOffset - * @param {MyGame.Example.Color} color - * @param {MyGame.Example.Any} testType - * @param {flatbuffers.Offset} testOffset - * @param {flatbuffers.Offset} test4Offset - * @param {flatbuffers.Offset} testarrayofstringOffset - * @param {flatbuffers.Offset} testarrayoftablesOffset - * @param {flatbuffers.Offset} enemyOffset - * @param {flatbuffers.Offset} testnestedflatbufferOffset - * @param {flatbuffers.Offset} testemptyOffset - * @param {boolean} testbool - * @param {number} testhashs32Fnv1 - * @param {number} testhashu32Fnv1 - * @param {flatbuffers.Long} testhashs64Fnv1 - * @param {flatbuffers.Long} testhashu64Fnv1 - * @param {number} testhashs32Fnv1a - * @param {number} testhashu32Fnv1a - * @param {flatbuffers.Long} testhashs64Fnv1a - * @param {flatbuffers.Long} testhashu64Fnv1a - * @param {flatbuffers.Offset} testarrayofboolsOffset - * @param {number} testf - * @param {number} testf2 - * @param {number} testf3 - * @param {flatbuffers.Offset} testarrayofstring2Offset - * @param {flatbuffers.Offset} testarrayofsortedstructOffset - * @param {flatbuffers.Offset} flexOffset - * @param {flatbuffers.Offset} test5Offset - * @param {flatbuffers.Offset} vectorOfLongsOffset - * @param {flatbuffers.Offset} vectorOfDoublesOffset - * @param {flatbuffers.Offset} parentNamespaceTestOffset - * @param {flatbuffers.Offset} vectorOfReferrablesOffset - * @param {flatbuffers.Long} singleWeakReference - * @param {flatbuffers.Offset} vectorOfWeakReferencesOffset - * @param {flatbuffers.Offset} vectorOfStrongReferrablesOffset - * @param {flatbuffers.Long} coOwningReference - * @param {flatbuffers.Offset} vectorOfCoOwningReferencesOffset - * @param {flatbuffers.Long} nonOwningReference - * @param {flatbuffers.Offset} vectorOfNonOwningReferencesOffset - * @param {MyGame.Example.AnyUniqueAliases} anyUniqueType - * @param {flatbuffers.Offset} anyUniqueOffset - * @param {MyGame.Example.AnyAmbiguousAliases} anyAmbiguousType - * @param {flatbuffers.Offset} anyAmbiguousOffset - * @param {flatbuffers.Offset} vectorOfEnumsOffset - * @param {MyGame.Example.Race} signedEnum - * @returns {flatbuffers.Offset} - */ -MyGame.Example.Monster.createMonster = function(builder, posOffset, mana, hp, nameOffset, inventoryOffset, color, testType, testOffset, test4Offset, testarrayofstringOffset, testarrayoftablesOffset, enemyOffset, testnestedflatbufferOffset, testemptyOffset, testbool, testhashs32Fnv1, testhashu32Fnv1, testhashs64Fnv1, testhashu64Fnv1, testhashs32Fnv1a, testhashu32Fnv1a, testhashs64Fnv1a, testhashu64Fnv1a, testarrayofboolsOffset, testf, testf2, testf3, testarrayofstring2Offset, testarrayofsortedstructOffset, flexOffset, test5Offset, vectorOfLongsOffset, vectorOfDoublesOffset, parentNamespaceTestOffset, vectorOfReferrablesOffset, singleWeakReference, vectorOfWeakReferencesOffset, vectorOfStrongReferrablesOffset, coOwningReference, vectorOfCoOwningReferencesOffset, nonOwningReference, vectorOfNonOwningReferencesOffset, anyUniqueType, anyUniqueOffset, anyAmbiguousType, anyAmbiguousOffset, vectorOfEnumsOffset, signedEnum) { - MyGame.Example.Monster.startMonster(builder); - MyGame.Example.Monster.addPos(builder, posOffset); - MyGame.Example.Monster.addMana(builder, mana); - MyGame.Example.Monster.addHp(builder, hp); - MyGame.Example.Monster.addName(builder, nameOffset); - MyGame.Example.Monster.addInventory(builder, inventoryOffset); - MyGame.Example.Monster.addColor(builder, color); - MyGame.Example.Monster.addTestType(builder, testType); - MyGame.Example.Monster.addTest(builder, testOffset); - MyGame.Example.Monster.addTest4(builder, test4Offset); - MyGame.Example.Monster.addTestarrayofstring(builder, testarrayofstringOffset); - MyGame.Example.Monster.addTestarrayoftables(builder, testarrayoftablesOffset); - MyGame.Example.Monster.addEnemy(builder, enemyOffset); - MyGame.Example.Monster.addTestnestedflatbuffer(builder, testnestedflatbufferOffset); - MyGame.Example.Monster.addTestempty(builder, testemptyOffset); - MyGame.Example.Monster.addTestbool(builder, testbool); - MyGame.Example.Monster.addTesthashs32Fnv1(builder, testhashs32Fnv1); - MyGame.Example.Monster.addTesthashu32Fnv1(builder, testhashu32Fnv1); - MyGame.Example.Monster.addTesthashs64Fnv1(builder, testhashs64Fnv1); - MyGame.Example.Monster.addTesthashu64Fnv1(builder, testhashu64Fnv1); - MyGame.Example.Monster.addTesthashs32Fnv1a(builder, testhashs32Fnv1a); - MyGame.Example.Monster.addTesthashu32Fnv1a(builder, testhashu32Fnv1a); - MyGame.Example.Monster.addTesthashs64Fnv1a(builder, testhashs64Fnv1a); - MyGame.Example.Monster.addTesthashu64Fnv1a(builder, testhashu64Fnv1a); - MyGame.Example.Monster.addTestarrayofbools(builder, testarrayofboolsOffset); - MyGame.Example.Monster.addTestf(builder, testf); - MyGame.Example.Monster.addTestf2(builder, testf2); - MyGame.Example.Monster.addTestf3(builder, testf3); - MyGame.Example.Monster.addTestarrayofstring2(builder, testarrayofstring2Offset); - MyGame.Example.Monster.addTestarrayofsortedstruct(builder, testarrayofsortedstructOffset); - MyGame.Example.Monster.addFlex(builder, flexOffset); - MyGame.Example.Monster.addTest5(builder, test5Offset); - MyGame.Example.Monster.addVectorOfLongs(builder, vectorOfLongsOffset); - MyGame.Example.Monster.addVectorOfDoubles(builder, vectorOfDoublesOffset); - MyGame.Example.Monster.addParentNamespaceTest(builder, parentNamespaceTestOffset); - MyGame.Example.Monster.addVectorOfReferrables(builder, vectorOfReferrablesOffset); - MyGame.Example.Monster.addSingleWeakReference(builder, singleWeakReference); - MyGame.Example.Monster.addVectorOfWeakReferences(builder, vectorOfWeakReferencesOffset); - MyGame.Example.Monster.addVectorOfStrongReferrables(builder, vectorOfStrongReferrablesOffset); - MyGame.Example.Monster.addCoOwningReference(builder, coOwningReference); - MyGame.Example.Monster.addVectorOfCoOwningReferences(builder, vectorOfCoOwningReferencesOffset); - MyGame.Example.Monster.addNonOwningReference(builder, nonOwningReference); - MyGame.Example.Monster.addVectorOfNonOwningReferences(builder, vectorOfNonOwningReferencesOffset); - MyGame.Example.Monster.addAnyUniqueType(builder, anyUniqueType); - MyGame.Example.Monster.addAnyUnique(builder, anyUniqueOffset); - MyGame.Example.Monster.addAnyAmbiguousType(builder, anyAmbiguousType); - MyGame.Example.Monster.addAnyAmbiguous(builder, anyAmbiguousOffset); - MyGame.Example.Monster.addVectorOfEnums(builder, vectorOfEnumsOffset); - MyGame.Example.Monster.addSignedEnum(builder, signedEnum); - return MyGame.Example.Monster.endMonster(builder); -} - /** * @constructor */ diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts index 34e09bcea23..b9918f07916 100644 --- a/tests/monster_test_generated.ts +++ b/tests/monster_test_generated.ts @@ -2949,58 +2949,6 @@ static finishSizePrefixedMonsterBuffer(builder:flatbuffers.Builder, offset:flatb builder.finish(offset, 'MONS', true); }; -static createMonster(builder:flatbuffers.Builder, posOffset:flatbuffers.Offset, mana:number, hp:number, nameOffset:flatbuffers.Offset, inventoryOffset:flatbuffers.Offset, color:MyGame.Example.Color, testType:MyGame.Example.Any, testOffset:flatbuffers.Offset, test4Offset:flatbuffers.Offset, testarrayofstringOffset:flatbuffers.Offset, testarrayoftablesOffset:flatbuffers.Offset, enemyOffset:flatbuffers.Offset, testnestedflatbufferOffset:flatbuffers.Offset, testemptyOffset:flatbuffers.Offset, testbool:boolean, testhashs32Fnv1:number, testhashu32Fnv1:number, testhashs64Fnv1:flatbuffers.Long, testhashu64Fnv1:flatbuffers.Long, testhashs32Fnv1a:number, testhashu32Fnv1a:number, testhashs64Fnv1a:flatbuffers.Long, testhashu64Fnv1a:flatbuffers.Long, testarrayofboolsOffset:flatbuffers.Offset, testf:number, testf2:number, testf3:number, testarrayofstring2Offset:flatbuffers.Offset, testarrayofsortedstructOffset:flatbuffers.Offset, flexOffset:flatbuffers.Offset, test5Offset:flatbuffers.Offset, vectorOfLongsOffset:flatbuffers.Offset, vectorOfDoublesOffset:flatbuffers.Offset, parentNamespaceTestOffset:flatbuffers.Offset, vectorOfReferrablesOffset:flatbuffers.Offset, singleWeakReference:flatbuffers.Long, vectorOfWeakReferencesOffset:flatbuffers.Offset, vectorOfStrongReferrablesOffset:flatbuffers.Offset, coOwningReference:flatbuffers.Long, vectorOfCoOwningReferencesOffset:flatbuffers.Offset, nonOwningReference:flatbuffers.Long, vectorOfNonOwningReferencesOffset:flatbuffers.Offset, anyUniqueType:MyGame.Example.AnyUniqueAliases, anyUniqueOffset:flatbuffers.Offset, anyAmbiguousType:MyGame.Example.AnyAmbiguousAliases, anyAmbiguousOffset:flatbuffers.Offset, vectorOfEnumsOffset:flatbuffers.Offset, signedEnum:MyGame.Example.Race):flatbuffers.Offset { - Monster.startMonster(builder); - Monster.addPos(builder, posOffset); - Monster.addMana(builder, mana); - Monster.addHp(builder, hp); - Monster.addName(builder, nameOffset); - Monster.addInventory(builder, inventoryOffset); - Monster.addColor(builder, color); - Monster.addTestType(builder, testType); - Monster.addTest(builder, testOffset); - Monster.addTest4(builder, test4Offset); - Monster.addTestarrayofstring(builder, testarrayofstringOffset); - Monster.addTestarrayoftables(builder, testarrayoftablesOffset); - Monster.addEnemy(builder, enemyOffset); - Monster.addTestnestedflatbuffer(builder, testnestedflatbufferOffset); - Monster.addTestempty(builder, testemptyOffset); - Monster.addTestbool(builder, testbool); - Monster.addTesthashs32Fnv1(builder, testhashs32Fnv1); - Monster.addTesthashu32Fnv1(builder, testhashu32Fnv1); - Monster.addTesthashs64Fnv1(builder, testhashs64Fnv1); - Monster.addTesthashu64Fnv1(builder, testhashu64Fnv1); - Monster.addTesthashs32Fnv1a(builder, testhashs32Fnv1a); - Monster.addTesthashu32Fnv1a(builder, testhashu32Fnv1a); - Monster.addTesthashs64Fnv1a(builder, testhashs64Fnv1a); - Monster.addTesthashu64Fnv1a(builder, testhashu64Fnv1a); - Monster.addTestarrayofbools(builder, testarrayofboolsOffset); - Monster.addTestf(builder, testf); - Monster.addTestf2(builder, testf2); - Monster.addTestf3(builder, testf3); - Monster.addTestarrayofstring2(builder, testarrayofstring2Offset); - Monster.addTestarrayofsortedstruct(builder, testarrayofsortedstructOffset); - Monster.addFlex(builder, flexOffset); - Monster.addTest5(builder, test5Offset); - Monster.addVectorOfLongs(builder, vectorOfLongsOffset); - Monster.addVectorOfDoubles(builder, vectorOfDoublesOffset); - Monster.addParentNamespaceTest(builder, parentNamespaceTestOffset); - Monster.addVectorOfReferrables(builder, vectorOfReferrablesOffset); - Monster.addSingleWeakReference(builder, singleWeakReference); - Monster.addVectorOfWeakReferences(builder, vectorOfWeakReferencesOffset); - Monster.addVectorOfStrongReferrables(builder, vectorOfStrongReferrablesOffset); - Monster.addCoOwningReference(builder, coOwningReference); - Monster.addVectorOfCoOwningReferences(builder, vectorOfCoOwningReferencesOffset); - Monster.addNonOwningReference(builder, nonOwningReference); - Monster.addVectorOfNonOwningReferences(builder, vectorOfNonOwningReferencesOffset); - Monster.addAnyUniqueType(builder, anyUniqueType); - Monster.addAnyUnique(builder, anyUniqueOffset); - Monster.addAnyAmbiguousType(builder, anyAmbiguousType); - Monster.addAnyAmbiguous(builder, anyAmbiguousOffset); - Monster.addVectorOfEnums(builder, vectorOfEnumsOffset); - Monster.addSignedEnum(builder, signedEnum); - return Monster.endMonster(builder); -} /** * @returns MonsterT diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js index f3be57867bf..b1969df79b0 100644 --- a/tests/namespace_test/namespace_test2_generated.js +++ b/tests/namespace_test/namespace_test2_generated.js @@ -144,21 +144,6 @@ NamespaceA.TableInFirstNS.endTableInFirstNS = function(builder) { return offset; }; -/** - * @param {flatbuffers.Builder} builder - * @param {flatbuffers.Offset} fooTableOffset - * @param {NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS} fooEnum - * @param {flatbuffers.Offset} fooStructOffset - * @returns {flatbuffers.Offset} - */ -NamespaceA.TableInFirstNS.createTableInFirstNS = function(builder, fooTableOffset, fooEnum, fooStructOffset) { - NamespaceA.TableInFirstNS.startTableInFirstNS(builder); - NamespaceA.TableInFirstNS.addFooTable(builder, fooTableOffset); - NamespaceA.TableInFirstNS.addFooEnum(builder, fooEnum); - NamespaceA.TableInFirstNS.addFooStruct(builder, fooStructOffset); - return NamespaceA.TableInFirstNS.endTableInFirstNS(builder); -} - /** * @constructor */ @@ -254,19 +239,6 @@ NamespaceC.TableInC.endTableInC = function(builder) { return offset; }; -/** - * @param {flatbuffers.Builder} builder - * @param {flatbuffers.Offset} referToA1Offset - * @param {flatbuffers.Offset} referToA2Offset - * @returns {flatbuffers.Offset} - */ -NamespaceC.TableInC.createTableInC = function(builder, referToA1Offset, referToA2Offset) { - NamespaceC.TableInC.startTableInC(builder); - NamespaceC.TableInC.addReferToA1(builder, referToA1Offset); - NamespaceC.TableInC.addReferToA2(builder, referToA2Offset); - return NamespaceC.TableInC.endTableInC(builder); -} - /** * @constructor */ diff --git a/tests/namespace_test/namespace_test2_generated.ts b/tests/namespace_test/namespace_test2_generated.ts index 6b4549d02f5..d5a1cf0c29d 100644 --- a/tests/namespace_test/namespace_test2_generated.ts +++ b/tests/namespace_test/namespace_test2_generated.ts @@ -120,13 +120,6 @@ static endTableInFirstNS(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; }; -static createTableInFirstNS(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offset, fooEnum:NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS, fooStructOffset:flatbuffers.Offset):flatbuffers.Offset { - TableInFirstNS.startTableInFirstNS(builder); - TableInFirstNS.addFooTable(builder, fooTableOffset); - TableInFirstNS.addFooEnum(builder, fooEnum); - TableInFirstNS.addFooStruct(builder, fooStructOffset); - return TableInFirstNS.endTableInFirstNS(builder); -} /** * @returns TableInFirstNST @@ -263,12 +256,6 @@ static endTableInC(builder:flatbuffers.Builder):flatbuffers.Offset { return offset; }; -static createTableInC(builder:flatbuffers.Builder, referToA1Offset:flatbuffers.Offset, referToA2Offset:flatbuffers.Offset):flatbuffers.Offset { - TableInC.startTableInC(builder); - TableInC.addReferToA1(builder, referToA1Offset); - TableInC.addReferToA2(builder, referToA2Offset); - return TableInC.endTableInC(builder); -} /** * @returns TableInCT