Dart: missing import in generated file
Hi,
using a super simple schema with a single import, the generated file does not import the right dependency:
// file: foo.fbs
namespace myspace;
table Foo {
version: string;
}
// file: bar.fbs
include "foo.fbs";
namespace myspace;
table Bar {
version: Foo;
}
When I compile it using:
$ flatc --dart bar.fbs
it generate only the bar_myspace_generated.dart without the import of the foo_myspace_generated.dart file that is not generated at all.
I tried using a MacOS 12.6.1 (Apple Silicon M1 Pro) running a local compiled flatc 22.10.26 and a flatc-dart 2.0.5 version. Both does not works.
What's wrong? Thank you
I think you can use --gen-all flag to generate all files
Hi @enum-class thank you for your suggestion.
It is a strange behavior. If you try the test example it works without the --gen-all flag and generate all right files with the right imports, but if you enable the --gen-all flag it generate wrong files. Below the full example (a simplified version of the example into the repo):
// monster_test.fbs
include "include_test1.fbs";
namespace MyGame;
table InParentNamespace {}
namespace MyGame.Example2;
table Monster {} // Test having same name as below, but in different namespace.
namespace MyGame.Example;
union Any { Monster, MyGame.Example2.Monster }
union AnyUniqueAliases { M: Monster, M2: MyGame.Example2.Monster }
table Referrable {
id:ulong(key, hash:"fnv1a_64");
}
table Monster {
enemy:MyGame.Example.Monster;
parent_namespace_test:InParentNamespace;
vector_of_referrables:[Referrable];
any_unique:AnyUniqueAliases;
}
root_type Monster;
// include_test1.fbs
include "include_test2.fbs";
table TableA {
b:MyGame.OtherNameSpace.TableB;
}
// include_test2.fbs
namespace MyGame.OtherNameSpace;
table TableB {
version: uint8;
}
Using:
$ flatc --dart monster_test.fbs
I get 3 files:
- monster_test_my_game_generated.dart
- monster_test_my_game.example_generated.dart
- monster_test_my_game.example2_generated.dart
with the right imports each.
Using instead:
$ flatc --dart --gen-all monster_test.fbs
I get 5 files:
- monster_test_generated.dart
- monster_test_my_game_generated.dart
- monster_test_my_game.example_generated.dart
- monster_test_my_game.example2_generated.dart
- monster_test_my_game.other_name_space_generated.dart
with wrong imports in every file (not in the first one):
// this is a wrong not required import
import './monster_test_generated.dart' as ;
I hope this is helpful to investigate. Thank you.
I think the behavior of flatc --dart is like this:
-
It will generate separate dart files per namespace, and include them. For instance, in monster_test.fbs run it generated 3 files each for MyGame, MyGame.Example2, MyGame.Example namespace. Also, in foo/bar run, it generates just one file, because there is just one namespace (myspace) in foo and bar files.
-
By adding --gen-all flag, we force it to generate files that included. so in monster_test one we can see 2 more files one for include_test1.fbs that has TableA and one for include_test2.fbs that has TableB implementation. Also, in foo/bar example, by employing --gen-all flag, we force it to generate foo.fbs which is included.
-
And, the reason for weird import
import './monster_test_generated.dart' as ;is that it blindly import every file in each other. So it can not find the usage of TableA which is generated in monster_test_generated.dart in other files, so leave it blank :))
I am not good at writing, but I hope I explained the situation clearly.
I need your help @mgesmundo , Since I am not a expert dart developer, could you please help me to understand from a dart developer respective, what is the correct generate output files that should we expect ?
Thank you for your time @enum-class. Below I try to explain the dart point of view with another example.
header.fbs
namespace myspace;
table Header {
version: int;
}
foo.fbs
include "header.fbs";
namespace myspace;
table Foo {
header: Header;
}
bar.fbs
include "header.fbs";
namespace myspace;
table Bar {
header: Header;
}
As you can see both Foo and Bar schemas include the Header schema and all three files use the same namespace myspace.
When I try to compile every file using:
$ flatc --dart header.fbs
$ flatc --dart foo.fbs
$ flatc --dart bar.fbs
I see three generate files:
file header_myspace_generated.dart
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
library myspace;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
class Header {
Header._(this._bc, this._bcOffset);
factory Header(List<int> bytes) {
final rootRef = fb.BufferContext.fromBytes(bytes);
...
}
}
foo_myspace_generated.dart
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
library myspace;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'header_myspace_generated.dart'; // <- this is the missing import
class Foo {
Foo._(this._bc, this._bcOffset);
factory Foo(List<int> bytes) {
final rootRef = fb.BufferContext.fromBytes(bytes);
...
}
}
bar_myspace_generated.dart
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
library myspace;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'header_myspace_generated.dart'; // <- this is the missing import
class Bar {
Bar._(this._bc, this._bcOffset);
factory Bar(List<int> bytes) {
final rootRef = fb.BufferContext.fromBytes(bytes);
...
}
}
The import 'header_myspace_generated.dart'; is missing in both Foo and Bar generated files.
If I use:
$ flatc --dart --gen-all foo.fbs
$ flatc --dart --gen-all bar.fbs
the two generated files do not need the Header generated file because have a duplicated declaration of the Header class inside every file, that is not optimal behavior.
I hope I have explained better. Thank you.
Thank you @enum-class and @dbaileychess for this update. Unfortunately it still to not works as expected. Using:
$ flatc --dart header.fbs
$ flatc --dart foo.fbs
$ flatc --dart bar.fbs
both foo_myspace_generated.dart and bar_myspace_generated.dart contains the Header import:
import './header_myspace_generated.dart' as myspace;
but the generated code use Header instead of myspace.Header (like the import 'package:flat_buffers/flat_buffers.dart' as fb; does).
If I remove the alias into the import:
import './header_myspace_generated.dart';
it works but it could create ambiguous imports in case of same class names into different packages imports. I'm sorry for this bad news. Thank you for your support.
The problem in foo/bar example in this issue is, it does not specified which Header in which namespace should be used. I mean It should be like this: header.fbs:
namespace myspace;
table Header {
version: int;
}
bar.fbs
include "header.fbs";
namespace myspace;
table Bar {
header: myspace.Header; /// => Not Header
}
Hi @enum-class, even if I add the full namespace, the result is the same:
header.fbs
namespace myspace;
table Header {
version: int;
}
bar.fbs
include "header.fbs";
namespace myspace;
table Bar {
header: myspace.Header;
}
Into the terminal:
flatc --dart bar.fbs
bar_myspace_generated.dart
// automatically generated by the FlatBuffers compiler, do not modify
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable
library myspace;
import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
// this is right!
import './header_myspace_generated.dart' as myspace;
class Bar {
Bar._(this._bc, this._bcOffset);
factory Bar(List<int> bytes) {
final rootRef = fb.BufferContext.fromBytes(bytes);
return reader.read(rootRef, 0);
}
static const fb.Reader<Bar> reader = _BarReader();
final fb.BufferContext _bc;
final int _bcOffset;
// this is wrong
Header? get header => Header.reader.vTableGetNullable(_bc, _bcOffset, 4);
// it should be:
// myspace.Header? get header => myspace.Header.reader.vTableGetNullable(_bc, _bcOffset, 4);
@override
String toString() {
return 'Bar{header: ${header}}';
}
}
Note that using:
flatc --dart --gen-all bar.fbs
the generate file contains all the Header classes but also contains the redundant (because all classes are inside the same file):
import './header_myspace_generated.dart' as myspace;
@mgesmundo the generator compare the namespace of Header and current namespace, find out both are same, so it drop namesapce (myspace). Change Header namespace to something else and try.
Hi @enum-class thank you for your best support! Yes: using a different namespace it works even if I don't understand why this is de default behaviour for Dart. My colleague that uses Golang do not have this behaviour.
It seems that the previous commit did not work properly on the latest Dart compiler, so I made some adjustments and now it runs normally locally.