orderedLibraryAssetIds method
Returns a ordered set of library asset ids ordered in reverse topological dependency order.
- If a file B includes a file A, then A will be appear before B.
- Throws
ErrorOf
if a dependency cycle is detected.
Implementation
Future<Set<AssetId>> orderedLibraryAssetIds(BuildStep buildStep) async {
final assetGraph =
DirectedGraph<AssetId>({}, comparator: ((v1, v2) => -v1.compareTo(v2)));
// An assetId map of all input libraries with the uri as key.
final assetMap = <Uri, AssetId>{};
// Access libraries
await for (final input in buildStep.findAssets(Glob(inputFiles))) {
// Check if input file is a library.
if (await buildStep.resolver.isLibrary(input)) {
assetMap[input.uri] = input;
assetGraph.addEdges(assetMap[input.uri]!, {});
}
}
for (final assetId in assetGraph) {
final importedAsseIds = <AssetId>{};
// Read library.
final library = await buildStep.resolver.libraryFor(assetId);
// Get dependencies
for (final import in library.libraryImports) {
final uri = Uri.parse(import.uri.toString());
// Skip if uri scheme is not "package" or "asset".
if (uri.scheme == 'package' ||
uri.scheme == 'asset' ||
uri.scheme == '') {
// Normalise uri to handle relative and package import directives.
final importedAssetId = AssetId.resolve(uri, from: assetId);
// Add vertex matching import directive.
if (assetMap[importedAssetId.uri] != null) {
importedAsseIds.add(assetMap[importedAssetId.uri]!);
}
}
}
assetGraph.addEdges(assetId, importedAsseIds);
}
final topologicalOrdering = assetGraph.sortedTopologicalOrdering;
if (topologicalOrdering == null) {
// Find the first cycle
final cycle = assetGraph.cycle;
throw ErrorOf<SyntheticBuilder>(
message: 'Circular dependency detected.',
expectedState: 'Input files must not include each other. '
'Alternatively, set constructor parameter "sortAssets: false".',
invalidState: 'File ${cycle.join(' imports ')}.');
}
// Return reversed topological ordering of asset ids.
return topologicalOrdering;
}