mirror of https://github.com/AMT-Cheif/drift.git
Draft for drift file discovery
This commit is contained in:
parent
5e4a65eace
commit
f82ea5936d
|
@ -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<Uri, FileState> knownFiles = {};
|
||||
final Map<DriftElementId, PendingDriftElement> 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<Dependency> dependencies;
|
||||
|
||||
bool cleanState = false;
|
||||
bool isOnCircularReferencePath = false;
|
||||
|
||||
PendingDriftElement(this.ownId, List<Dependency> 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<DriftElementId> locallyDefinedElements = [];
|
||||
final List<Uri> directImports = [];
|
||||
final List<AnalysisError> errors = [];
|
||||
|
||||
bool contentsFresh = false;
|
||||
bool referencesFresh = false;
|
||||
|
||||
FileKind? kind;
|
||||
DriftFile? parsedDriftFile;
|
||||
LibraryElement? parsedDartFile;
|
||||
|
||||
FileState(this.uri);
|
||||
|
||||
String get extension => url.extension(uri.path);
|
||||
}
|
|
@ -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<void> _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<void> fullyAnalyze(Uri uri) async {
|
||||
var known = cache.knownFiles[uri];
|
||||
|
||||
if (known == null || !known.contentsFresh) {
|
||||
await _discover(cache.notifyFileChanged(uri));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import '../results/element.dart';
|
||||
import 'state.dart';
|
||||
|
||||
class DriftAnalysisCache {
|
||||
final Map<Uri, FileState> knownFiles = {};
|
||||
final Map<DriftElementId, DiscoveredElement> 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) {}
|
||||
}
|
|
@ -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<void> fullyAnalyze(Uri uri) async {
|
||||
var known = cache.knownFiles[uri];
|
||||
|
||||
if (known == null || known.discovery == null) {
|
||||
await DiscoverStep(this, cache.notifyFileChanged(uri)).discover();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<AnalysisError> errorsDuringDiscovery = [];
|
||||
final List<AnalysisError> errorsDuringAnalysis = [];
|
||||
|
||||
FileState(this.ownUri);
|
||||
|
||||
String get extension => url.extension(ownUri.path);
|
||||
}
|
||||
|
||||
abstract class DiscoveredFileState {
|
||||
final List<DiscoveredElement> 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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
class DependencyCollector {}
|
|
@ -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<void> discover() async {
|
||||
final extension = _file.extension;
|
||||
final pendingElements = <DiscoveredElement>[];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
class AnalyzedFile {}
|
|
@ -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);
|
||||
}
|
|
@ -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<String> readAsString(Uri uri) {
|
||||
return _buildStep.readAsString(AssetId.resolve(uri));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LibraryElement> readDart(Uri uri) {
|
||||
return _buildStep.resolver.libraryFor(AssetId.resolve(uri));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue