import '../results/element.dart'; import 'state.dart'; /// An in-memory cache of analysis results for drift elements. /// /// At the moment, the cache is not set up to handle changing files. class DriftAnalysisCache { final Map> serializedElements = {}; final Map knownFiles = {}; final Map discoveredElements = {}; FileState stateForUri(Uri uri) { return knownFiles[uri] ?? notifyFileChanged(uri); } FileState notifyFileChanged(Uri uri) { // todo: Mark references for files that import this one as stale. // todo: Mark elements that reference an element in this file as stale. serializedElements.remove(uri); return knownFiles.putIfAbsent(uri, () => FileState(uri)) ..errorsDuringDiscovery.clear() ..analysis.clear() ..discovery = null; } void notifyFileDeleted(Uri uri) {} void postFileDiscoveryResults(FileState state) { discoveredElements.removeWhere((key, _) => key.libraryUri == state.ownUri); final discovery = state.discovery; if (discovery != null) { discoveredElements.addAll({ for (final definedHere in discovery.locallyDefinedElements) definedHere.ownId: definedHere, }); } } /// From a given [entrypoint], yield the [entrypoint] itself and all /// transitive imports. /// /// This assumes that pre-analysis has already happened for all transitive /// imports, meaning that [knownFiles] contains an entry for every import URI. Iterable crawl(FileState entrypoint) { return crawlMulti([entrypoint]); } /// Crawls all dependencies from a set of [entrypoints]. Iterable crawlMulti(Iterable entrypoints) sync* { final seenUris = {}; final pending = []; for (final initial in entrypoints) { if (seenUris.add(initial.ownUri)) { pending.add(initial); } } while (pending.isNotEmpty) { final found = pending.removeLast(); yield found; for (final imported in found.discovery?.importDependencies ?? const []) { if (seenUris.add(imported)) { pending.add(knownFiles[imported]!); } } } } }