import 'package:analyzer/dart/element/element.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' show url; import 'package:sqlparser/sqlparser.dart' hide AnalysisError; import '../results/database.dart'; import '../results/element.dart'; import '../results/file_results.dart'; import '../results/query.dart'; import 'driver.dart'; import 'error.dart'; class FileState { final Uri ownUri; DiscoveredFileState? discovery; final List errorsDuringDiscovery = []; final Map analysis = {}; FileAnalysisResult? fileAnalysis; bool? _needsModularAccessor; FileState(this.ownUri); String get extension => url.extension(ownUri.path); /// Whether this file contains a drift database or a drift accessor / DAO. bool get containsDatabaseAccessor { return analyzedElements.any((e) => e is BaseDriftAccessor); } /// All analyzed [DriftElement]s found in this library. @visibleForTesting Iterable get analyzedElements { return analysis.values.map((e) => e.result).whereType(); } Iterable get allErrors sync* { yield* errorsDuringDiscovery; for (final entry in analysis.values) { yield* entry.errorsDuringAnalysis; } final fileResults = fileAnalysis; if (fileResults != null) { yield* fileResults.analysisErrors; } } bool get isFullyAnalyzed { return discovery != null && discovery!.locallyDefinedElements .every((e) => elementIsAnalyzed(e.ownId)); } DriftElementId id(String name) => DriftElementId(ownUri, name); bool elementIsAnalyzed(DriftElementId id) { return analysis[id]?.isUpToDate == true; } bool get _definesQuery { return analyzedElements.any((e) => e is DefinedSqlQuery); } /// Whether an accessor class making queries and imports available should be /// written for this file if modular analysis is enabled. /// /// This is the case if this accessor defines queries or if it transitively /// imports a modular accessor. bool needsModularAccessor(DriftAnalysisDriver driver) { if (_needsModularAccessor != null) return _needsModularAccessor!; return _needsModularAccessor = driver.cache.crawl(this).any((e) { return e._definesQuery; }); } } abstract class DiscoveredFileState { final List locallyDefinedElements; bool get isValidImport => false; Iterable get importDependencies => const []; DiscoveredFileState(this.locallyDefinedElements); } class DiscoveredDriftFile extends DiscoveredFileState { final String originalSource; final DriftFile ast; final List imports; @override bool get isValidImport => true; @override Iterable get importDependencies => imports.map((e) => e.importedUri); DiscoveredDriftFile({ required this.originalSource, required this.ast, required this.imports, required List locallyDefinedElements, }) : super(locallyDefinedElements); } class DriftFileImport { final ImportStatement ast; final Uri importedUri; DriftFileImport(this.ast, this.importedUri); } class DiscoveredDartLibrary extends DiscoveredFileState { final LibraryElement library; @override bool get isValidImport => true; DiscoveredDartLibrary(this.library, super.locallyDefinedElements); } class NotADartLibrary extends DiscoveredFileState { NotADartLibrary() : super(const []); } class NoSuchFile extends DiscoveredFileState { NoSuchFile() : super(const []); } class UnknownFile extends DiscoveredFileState { UnknownFile() : super(const []); } abstract class DiscoveredElement { final DriftElementId ownId; DiscoveredElement(this.ownId); @override String toString() { return '$runtimeType:$ownId'; } } class ElementAnalysisState { final DriftElementId ownId; final List errorsDuringAnalysis = []; DriftElement? result; bool isUpToDate = false; ElementAnalysisState(this.ownId); }