Support emitting to a part file (`.g.dart`)
Opened this issue · 3 comments
I have a generator that emits to the shared .g.dart
file, but it doesn't appear to work if the source file has aliased imports.
Of course, i cant add any imports myself due to being a part file, so how do I make use of the pre-existing aliased imports?
I'm defining urls in Reference/refer as normal, but I cant seem to find an option that correctly uses the aliased imports without generating imports ourselves, as part files cant have imports.
Did you find a solution to this?
I did some digging in the code to figure out how to achieve an automated handling of imports. As you mentioned there is no functionality built in to deal with this today.
But it was fairly easy to implement a solution!
The imports are handled by the Allocator
class and can be injected to the DartEmitter
when generating the code. Unfortunately, there are only 3 different implementations of the Allocator that either resolve no imports, all imports in the file without prefixes, and all imports in the file with prefixes.
But you can create your own implementation, I added two new Allocators one PartOfAllocator
and one PartAllocator
.
These will preserve the state and keep the prefixes in sync between the part of
and the part
file.
class PartOfAllocator implements Allocator {
static final _doNotPrefix = ['dart:core'];
final _imports = <String, int>{};
var _keys = 1;
PartOfAllocator(List<String>? doNotPrefix) {
_doNotPrefix.addAll(doNotPrefix ?? []);
}
@override
String allocate(Reference reference) {
final symbol = reference.symbol;
final url = reference.url;
if (url == null || _doNotPrefix.contains(url)) {
return symbol!;
}
return '_i${_imports.putIfAbsent(url, _nextKey)}.$symbol';
}
int _nextKey() => _keys++;
@override
Iterable<Directive> get imports => [];
}
class PartAllocator implements Allocator {
PartOfAllocator _partOfAllocator;
PartAllocator._(this._partOfAllocator);
factory PartAllocator(PartOfAllocator partOfAllocator) {
return PartAllocator._(partOfAllocator);
}
@override
String allocate(Reference reference) {
return _partOfAllocator.allocate(reference);
}
@override
Iterable<Directive> get imports => _partOfAllocator._imports.keys.map(
(u) => Directive.import(u, as: '_i${_partOfAllocator._imports[u]}'),
);
}
Then you can use the allocators when generating the dart code like so:
final partOfAllocator = PartOfAllocator();
final partOfFile = Library(...).accept(DartEmitter(allocator: partOfAllocator)).toString()
final partFile = Library(...).accept(DartEmitter(allocator: PartAllocator(partOfAllocator))).toString()
I may create a PR with these later when I have time!
@Isakdl I'm seeing a lot of _i
Where's the "use existing imports and aliases" option?