chore: adopt Dart 3.9 toolchain — honest floor + tall-style reformat (T-353)

Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).

Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
  - whole-tree `dart format` reformat (tall style)
  - `dart fix` for unnecessary_underscores + use_null_aware_elements

No runtime behaviour change; `make test` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 12:11:53 +02:00
co-authored by Claude Opus 4.8
parent bcea5f15b7
commit 6d0ebab721
444 changed files with 7587 additions and 12849 deletions
+2 -10
View File
@@ -18,13 +18,7 @@ library;
/// A single parsed gitignore pattern.
class IgnorePattern {
IgnorePattern._({
required this.source,
required this.negated,
required this.directoryOnly,
required this.anchored,
required this.regex,
});
IgnorePattern._({required this.source, required this.negated, required this.directoryOnly, required this.anchored, required this.regex});
/// The raw line from the file (for diagnostics).
final String source;
@@ -168,7 +162,5 @@ class IgnoreSet {
/// ignore files. Matches D-004's "walker magic: none except
/// `.git/`" — but the tree-view UI benefits from hiding `.pql/` and
/// `.dart_tool/` too since users never edit those by hand.
static IgnoreSet builtin() => IgnoreSet.parse(const [
'.git/\n.pql/\n.clide/\n.dart_tool/\nbuild/\nnode_modules/\n',
]);
static IgnoreSet builtin() => IgnoreSet.parse(const ['.git/\n.pql/\n.clide/\n.dart_tool/\nbuild/\nnode_modules/\n']);
}
+20 -33
View File
@@ -10,14 +10,7 @@ import 'dart:io';
import 'ignore.dart';
class FileEntry {
const FileEntry({
required this.name,
required this.path,
required this.isDirectory,
required this.isSymlink,
this.sizeBytes,
this.modifiedMs,
});
const FileEntry({required this.name, required this.path, required this.isDirectory, required this.isSymlink, this.sizeBytes, this.modifiedMs});
/// Display name (basename).
final String name;
@@ -30,23 +23,19 @@ class FileEntry {
final int? modifiedMs;
Map<String, Object?> toJson() => {
'name': name,
'path': path,
'isDirectory': isDirectory,
'isSymlink': isSymlink,
if (sizeBytes != null) 'sizeBytes': sizeBytes,
if (modifiedMs != null) 'modifiedMs': modifiedMs,
};
'name': name,
'path': path,
'isDirectory': isDirectory,
'isSymlink': isSymlink,
if (sizeBytes != null) 'sizeBytes': sizeBytes,
if (modifiedMs != null) 'modifiedMs': modifiedMs,
};
}
/// List the immediate children of [dir] (repo-relative path) under
/// [root]. Filters against [ignore]. Returns entries sorted
/// directory-first, then by name.
Future<List<FileEntry>> listDir({
required Directory root,
required String dir,
required IgnoreSet ignore,
}) async {
Future<List<FileEntry>> listDir({required Directory root, required String dir, required IgnoreSet ignore}) async {
final resolved = dir.isEmpty ? root : Directory('${root.absolute.path}${Platform.pathSeparator}${dir.replaceAll('/', Platform.pathSeparator)}');
if (!await resolved.exists()) return const [];
@@ -57,14 +46,16 @@ Future<List<FileEntry>> listDir({
final stat = await e.stat();
final isDir = stat.type == FileSystemEntityType.directory;
if (ignore.isIgnored(rel, isDirectory: isDir)) continue;
entries.add(FileEntry(
name: name,
path: rel,
isDirectory: isDir,
isSymlink: stat.type == FileSystemEntityType.link,
sizeBytes: isDir ? null : stat.size,
modifiedMs: stat.modified.millisecondsSinceEpoch,
));
entries.add(
FileEntry(
name: name,
path: rel,
isDirectory: isDir,
isSymlink: stat.type == FileSystemEntityType.link,
sizeBytes: isDir ? null : stat.size,
modifiedMs: stat.modified.millisecondsSinceEpoch,
),
);
}
entries.sort((a, b) {
@@ -96,11 +87,7 @@ class WalkResult {
/// cap is hit the walk stops early and [WalkResult.truncated] is set so
/// callers can surface "results truncated". The returned list is sorted
/// by repo-relative path for a deterministic contract.
Future<WalkResult> walkFiles({
required Directory root,
required IgnoreSet ignore,
int maxFiles = 50000,
}) async {
Future<WalkResult> walkFiles({required Directory root, required IgnoreSet ignore, int maxFiles = 50000}) async {
final out = <FileEntry>[];
// DFS over repo-relative directory paths; '' is the root itself.
final stack = <String>[''];
+4 -19
View File
@@ -38,11 +38,7 @@ enum FileChangeKind {
}
class FileChange {
const FileChange({
required this.kind,
required this.path,
required this.isDirectory,
});
const FileChange({required this.kind, required this.path, required this.isDirectory});
final FileChangeKind kind;
@@ -50,11 +46,7 @@ class FileChange {
final String path;
final bool isDirectory;
Map<String, Object?> toJson() => {
'kind': kind.wire,
'path': path,
'isDirectory': isDirectory,
};
Map<String, Object?> toJson() => {'kind': kind.wire, 'path': path, 'isDirectory': isDirectory};
}
class FileWatcher {
@@ -70,10 +62,7 @@ class FileWatcher {
Future<void> start() async {
if (_sub != null) return;
_sub = root.watch(recursive: true).listen(
_onEvent,
onError: (Object e, StackTrace _) => _controller.addError(e),
);
_sub = root.watch(recursive: true).listen(_onEvent, onError: (Object e, StackTrace _) => _controller.addError(e));
}
Future<void> stop() async {
@@ -87,11 +76,7 @@ class FileWatcher {
if (rel == null) return;
final isDir = e.isDirectory;
if (_ignored(rel, isDir)) return;
_controller.add(FileChange(
kind: FileChangeKind.fromEvent(e),
path: rel,
isDirectory: isDir,
));
_controller.add(FileChange(kind: FileChangeKind.fromEvent(e), path: rel, isDirectory: isDir));
}
/// True if `rel` is ignored, or sits inside an ignored directory.