diff --git a/drift_dev/lib/src/analysis/cache.dart b/drift_dev/lib/src/analysis/cache.dart deleted file mode 100644 index 04b8f322..00000000 --- a/drift_dev/lib/src/analysis/cache.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:analyzer/dart/element/element.dart'; -import 'package:collection/collection.dart'; -import 'package:sqlparser/sqlparser.dart'; -import 'package:path/path.dart' show url; - -import 'results/element.dart'; - -class DriftAnalysisCache { - final Map knownFiles = {}; - final Map knownElements = {}; - - 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. - - return knownFiles.putIfAbsent(uri, () => FileState(uri)) - ..errors.clear() - ..kind = null - ..parsedDartFile = null - ..parsedDriftFile = null; - } - - void notifyFileDeleted(Uri uri) {} -} - -/// A [DriftElement] that is known to exist, but perhaps hasn't fully been -/// resolved yet. -class PendingDriftElement { - final DriftElementId ownId; - final List dependencies; - - bool cleanState = false; - bool isOnCircularReferencePath = false; - - PendingDriftElement(this.ownId, List dependencies) - : dependencies = UnmodifiableListView(dependencies); -} - -abstract class Dependency {} - -class ReferencesElement extends Dependency { - final DriftElementId referencedElement; - - ReferencesElement(this.referencedElement); -} - -class ReferencesUnknownElement extends Dependency { - final String name; - - ReferencesUnknownElement(this.name); -} - -enum FileKind { - driftFile, - dartLibrary, - - /// A Dart part file, a file with an unknown extension or a file that doesn't - /// exist. - invalid, -} - -class FileState { - final Uri uri; - - final List locallyDefinedElements = []; - final List directImports = []; - final List errors = []; - - bool contentsFresh = false; - bool referencesFresh = false; - - FileKind? kind; - DriftFile? parsedDriftFile; - LibraryElement? parsedDartFile; - - FileState(this.uri); - - String get extension => url.extension(uri.path); -} diff --git a/drift_dev/lib/src/analysis/driver.dart b/drift_dev/lib/src/analysis/driver.dart deleted file mode 100644 index c24a6542..00000000 --- a/drift_dev/lib/src/analysis/driver.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:sqlparser/sqlparser.dart'; - -import '../analyzer/options.dart'; -import 'backend.dart'; -import 'cache.dart'; - -class DriftAnalysisDriver { - final DriftBackend backend; - final DriftAnalysisCache cache = DriftAnalysisCache(); - final DriftOptions options; - - DriftAnalysisDriver(this.backend, this.options); - - SqlEngine _newSqlEngine() { - return SqlEngine( - EngineOptions( - useDriftExtensions: true, - enabledExtensions: [ - // todo: Map from options - ], - version: options.sqliteVersion, - ), - ); - } - - /// Identify all [PendingDriftElement]s in a file. - Future _discover(FileState state) async { - final extension = state.extension; - - switch (extension) { - case '.dart': - try { - state - ..parsedDartFile = await backend.readDart(state.uri) - ..kind = FileKind.dartLibrary; - } catch (e, s) { - backend.log - .fine('Could not read Dart library from ${state.uri}', e, s); - state.kind = FileKind.invalid; - } - break; - case '.drift': - case '.moor': - final engine = _newSqlEngine(); - String contents; - try { - contents = await backend.readAsString(state.uri); - state.kind = FileKind.driftFile; - } catch (e, s) { - backend.log.fine('Could not read drift sources ${state.uri}', e, s); - state.kind = FileKind.invalid; - break; - } - - // todo: Handle parse errors - final parsed = engine.parseDriftFile(contents); - state.parsedDriftFile = parsed.rootNode as DriftFile; - - break; - } - } - - Future fullyAnalyze(Uri uri) async { - var known = cache.knownFiles[uri]; - - if (known == null || !known.contentsFresh) { - await _discover(cache.notifyFileChanged(uri)); - } - } -} diff --git a/drift_dev/lib/src/analysis/driver/cache.dart b/drift_dev/lib/src/analysis/driver/cache.dart new file mode 100644 index 00000000..520b3aa5 --- /dev/null +++ b/drift_dev/lib/src/analysis/driver/cache.dart @@ -0,0 +1,20 @@ +import '../results/element.dart'; +import 'state.dart'; + +class DriftAnalysisCache { + final Map knownFiles = {}; + final Map knownElements = {}; + + 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. + + return knownFiles.putIfAbsent(uri, () => FileState(uri)) + ..errorsDuringDiscovery.clear() + ..errorsDuringAnalysis.clear() + ..results = null + ..discovery = null; + } + + void notifyFileDeleted(Uri uri) {} +} diff --git a/drift_dev/lib/src/analysis/driver/driver.dart b/drift_dev/lib/src/analysis/driver/driver.dart new file mode 100644 index 00000000..9ed7b196 --- /dev/null +++ b/drift_dev/lib/src/analysis/driver/driver.dart @@ -0,0 +1,34 @@ +import 'package:sqlparser/sqlparser.dart'; + +import '../../analyzer/options.dart'; +import '../backend.dart'; +import '../resolver/discover.dart'; +import 'cache.dart'; + +class DriftAnalysisDriver { + final DriftBackend backend; + final DriftAnalysisCache cache = DriftAnalysisCache(); + final DriftOptions options; + + DriftAnalysisDriver(this.backend, this.options); + + SqlEngine newSqlEngine() { + return SqlEngine( + EngineOptions( + useDriftExtensions: true, + enabledExtensions: [ + // todo: Map from options + ], + version: options.sqliteVersion, + ), + ); + } + + Future fullyAnalyze(Uri uri) async { + var known = cache.knownFiles[uri]; + + if (known == null || known.discovery == null) { + await DiscoverStep(this, cache.notifyFileChanged(uri)).discover(); + } + } +} diff --git a/drift_dev/lib/src/analysis/error.dart b/drift_dev/lib/src/analysis/driver/error.dart similarity index 100% rename from drift_dev/lib/src/analysis/error.dart rename to drift_dev/lib/src/analysis/driver/error.dart diff --git a/drift_dev/lib/src/analysis/driver/state.dart b/drift_dev/lib/src/analysis/driver/state.dart new file mode 100644 index 00000000..a814bce8 --- /dev/null +++ b/drift_dev/lib/src/analysis/driver/state.dart @@ -0,0 +1,53 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:path/path.dart' show url; +import 'package:sqlparser/sqlparser.dart' hide AnalysisError; + +import '../results/element.dart'; +import '../results/file.dart'; +import 'error.dart'; + +class FileState { + final Uri ownUri; + + DiscoveredFileState? discovery; + AnalyzedFile? results; + + final List errorsDuringDiscovery = []; + final List errorsDuringAnalysis = []; + + FileState(this.ownUri); + + String get extension => url.extension(ownUri.path); +} + +abstract class DiscoveredFileState { + final List locallyDefinedElements; + + DiscoveredFileState(this.locallyDefinedElements); +} + +class DiscoveredDriftFile extends DiscoveredFileState { + final DriftFile ast; + + DiscoveredDriftFile(this.ast, super.locallyDefinedElements); +} + +class DiscoveredDartLibrary extends DiscoveredFileState { + final LibraryElement library; + + DiscoveredDartLibrary(this.library, super.locallyDefinedElements); +} + +class NotADartLibrary extends DiscoveredFileState { + NotADartLibrary() : super(const []); +} + +class NoSuchFile extends DiscoveredFileState { + NoSuchFile() : super(const []); +} + +abstract class DiscoveredElement { + final DriftElementId ownId; + + DiscoveredElement(this.ownId); +} diff --git a/drift_dev/lib/src/analysis/resolver/dependency_collector.dart b/drift_dev/lib/src/analysis/resolver/dependency_collector.dart new file mode 100644 index 00000000..b0b0dbfb --- /dev/null +++ b/drift_dev/lib/src/analysis/resolver/dependency_collector.dart @@ -0,0 +1 @@ +class DependencyCollector {} diff --git a/drift_dev/lib/src/analysis/resolver/discover.dart b/drift_dev/lib/src/analysis/resolver/discover.dart new file mode 100644 index 00000000..71cd9d03 --- /dev/null +++ b/drift_dev/lib/src/analysis/resolver/discover.dart @@ -0,0 +1,61 @@ +import 'package:sqlparser/sqlparser.dart'; + +import '../driver/driver.dart'; +import '../driver/state.dart'; +import '../results/element.dart'; +import 'intermediate_state.dart'; + +class DiscoverStep { + final DriftAnalysisDriver _driver; + final FileState _file; + + DiscoverStep(this._driver, this._file); + + DriftElementId _id(String name) => DriftElementId(_file.ownUri, name); + + Future discover() async { + final extension = _file.extension; + final pendingElements = []; + + switch (extension) { + case '.dart': + try { + final library = await _driver.backend.readDart(_file.ownUri); + _file.discovery = DiscoveredDartLibrary(library, []); + } catch (e, s) { + _driver.backend.log + .fine('Could not read Dart library from ${_file.ownUri}', e, s); + _file.discovery = NotADartLibrary(); + } + break; + case '.drift': + case '.moor': + final engine = _driver.newSqlEngine(); + String contents; + try { + contents = await _driver.backend.readAsString(_file.ownUri); + } catch (e, s) { + _driver.backend.log + .fine('Could not read drift sources ${_file.ownUri}', e, s); + _file.discovery = NoSuchFile(); + break; + } + + // todo: Handle parse errors + final parsed = engine.parseDriftFile(contents); + final ast = parsed.rootNode as DriftFile; + + for (final node in ast.childNodes) { + if (node is TableInducingStatement) { + pendingElements + .add(DiscoveredDriftTable(_id(node.createdName), node)); + } else if (node is CreateViewStatement) { + pendingElements + .add(DiscoveredDriftView(_id(node.createdName), node)); + } + } + + break; + } + } +} diff --git a/drift_dev/lib/src/analysis/resolver/intermediate_state.dart b/drift_dev/lib/src/analysis/resolver/intermediate_state.dart new file mode 100644 index 00000000..f563c1ef --- /dev/null +++ b/drift_dev/lib/src/analysis/resolver/intermediate_state.dart @@ -0,0 +1,15 @@ +import 'package:sqlparser/sqlparser.dart'; + +import '../driver/state.dart'; + +class DiscoveredDriftTable extends DiscoveredElement { + final TableInducingStatement createTable; + + DiscoveredDriftTable(super.ownId, this.createTable); +} + +class DiscoveredDriftView extends DiscoveredElement { + final CreateViewStatement createView; + + DiscoveredDriftView(super.ownId, this.createView); +} diff --git a/drift_dev/lib/src/analysis/results/file.dart b/drift_dev/lib/src/analysis/results/file.dart new file mode 100644 index 00000000..add10ca2 --- /dev/null +++ b/drift_dev/lib/src/analysis/results/file.dart @@ -0,0 +1 @@ +class AnalyzedFile {} diff --git a/drift_dev/lib/src/analysis/runner/temporary_results.dart b/drift_dev/lib/src/analysis/runner/temporary_results.dart deleted file mode 100644 index 47f67710..00000000 --- a/drift_dev/lib/src/analysis/runner/temporary_results.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:sqlparser/sqlparser.dart'; - -abstract class TemporaryResult {} - -class TemporaryDriftTable extends TemporaryResult { - final TableInducingStatement statement; - - TemporaryDriftTable(this.statement); -} - -class TemporaryDriftView extends TemporaryResult { - final CreateViewStatement statement; - - TemporaryDriftView(this.statement); -} diff --git a/drift_dev/lib/src/backends/build/new_backend.dart b/drift_dev/lib/src/backends/build/new_backend.dart index 53d95c6c..4ea651d0 100644 --- a/drift_dev/lib/src/backends/build/new_backend.dart +++ b/drift_dev/lib/src/backends/build/new_backend.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/element/element.dart'; import 'package:logging/logging.dart'; import 'package:build/build.dart'; import 'package:build/build.dart' as build; @@ -16,4 +17,9 @@ class DriftBuildBackend extends DriftBackend { Future readAsString(Uri uri) { return _buildStep.readAsString(AssetId.resolve(uri)); } + + @override + Future readDart(Uri uri) { + return _buildStep.resolver.libraryFor(AssetId.resolve(uri)); + } }