[null-safety] migrate to _almost_ null safety (#162)

Remove record/replay functionality and update to almost null-safety.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index c6d2ad9..ee1a01b 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,4 +1,6 @@
 analyzer:
+  enable-experiment:
+    - non-nullable
   strong-mode:
     implicit-casts: false
     implicit-dynamic: false
diff --git a/appveyor.yml b/appveyor.yml
index 319ec41..27abf4b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -11,4 +11,4 @@
 build: off
 
 test_script:
-  - pub run test -j1
+  - pub run --enable-experiment=non-nullable test -j1
diff --git a/dev/bots/travis_script.sh b/dev/bots/travis_script.sh
index fe55e57..d601d39 100755
--- a/dev/bots/travis_script.sh
+++ b/dev/bots/travis_script.sh
@@ -11,10 +11,10 @@
   for package in "${PACKAGES[@]}"; do
     echo "Analyzing packages/$package"
     cd $ROOT/packages/$package
-    dartanalyzer --options=$ROOT/analysis_options.yaml . || exit $?
+    dartanalyzer --enable-experiment=non-nullable --options=$ROOT/analysis_options.yaml . || exit $?
   done
 else
   # tests shard
   cd $ROOT/packages/file
-  pub run test -j1 -rexpanded || exit $?
+  pub run --enable-experiment=non-nullable test -j1 -rexpanded || exit $?
 fi
diff --git a/packages/file/CHANGELOG.md b/packages/file/CHANGELOG.md
index 61d3529..46fffae 100644
--- a/packages/file/CHANGELOG.md
+++ b/packages/file/CHANGELOG.md
@@ -1,6 +1,8 @@
-#### 5.2.2-dev
+#### 6.0.0-nullsafety
 
-* Made `MemoryRandomAccessFile` and `MemoryFile.openWrite` handle the file
+* Update to null safety.
+* Remove record/replay functionality.
+* Made `MemoryRandomAccessFile` and `MemoryFile.openWrite` handle the file.
   being removed or renamed while open.
 * Fixed incorrect formatting in `NoMatchingInvocationError.toString()`.
 * Fixed more test flakiness.
diff --git a/packages/file/lib/chroot.dart b/packages/file/lib/chroot.dart
index 56d2bd5..3967fff 100644
--- a/packages/file/lib/chroot.dart
+++ b/packages/file/lib/chroot.dart
@@ -2,5 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// A file system that provides a view into _another_ `FileSystem` via a path.
 export 'src/backends/chroot.dart';
diff --git a/packages/file/lib/file.dart b/packages/file/lib/file.dart
index cdde9fe..07ee858 100644
--- a/packages/file/lib/file.dart
+++ b/packages/file/lib/file.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// Core interfaces containing the abstract `FileSystem` interface definition
 /// and all associated types used by `FileSystem`.
 export 'src/forwarding.dart';
diff --git a/packages/file/lib/local.dart b/packages/file/lib/local.dart
index 74f506e..773b000 100644
--- a/packages/file/lib/local.dart
+++ b/packages/file/lib/local.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// A local file system implementation. This relies on the use of `dart:io`
 /// and is thus not suitable for use in the browser.
 export 'src/backends/local.dart';
diff --git a/packages/file/lib/memory.dart b/packages/file/lib/memory.dart
index 31e90e7..b0d6c3e 100644
--- a/packages/file/lib/memory.dart
+++ b/packages/file/lib/memory.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// An implementation of `FileSystem` that exists entirely in memory with an
 /// internal representation loosely based on the Filesystem Hierarchy Standard.
 export 'src/backends/memory.dart';
diff --git a/packages/file/lib/record_replay.dart b/packages/file/lib/record_replay.dart
deleted file mode 100644
index be28576..0000000
--- a/packages/file/lib/record_replay.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// File systems that work together to record invocations during live operation
-/// and then play invocations back in tests.
-export 'src/backends/record_replay/errors.dart';
-export 'src/backends/record_replay/events.dart'
-    show InvocationEvent, PropertyGetEvent, PropertySetEvent, MethodEvent;
-export 'src/backends/record_replay/recording.dart';
-export 'src/backends/record_replay/recording_file_system.dart'
-    show RecordingFileSystem;
-export 'src/backends/record_replay/replay_file_system.dart'
-    show ReplayFileSystem;
diff --git a/packages/file/lib/src/backends/chroot.dart b/packages/file/lib/src/backends/chroot.dart
index 72ce3ca..7a9a1f0 100644
--- a/packages/file/lib/src/backends/chroot.dart
+++ b/packages/file/lib/src/backends/chroot.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 library file.src.backends.chroot;
 
 import 'dart:async';
diff --git a/packages/file/lib/src/backends/chroot/chroot_directory.dart b/packages/file/lib/src/backends/chroot/chroot_directory.dart
index 8fec7b1..74e3cd2 100644
--- a/packages/file/lib/src/backends/chroot/chroot_directory.dart
+++ b/packages/file/lib/src/backends/chroot/chroot_directory.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 part of file.src.backends.chroot;
 
 class _ChrootDirectory extends _ChrootFileSystemEntity<Directory, io.Directory>
diff --git a/packages/file/lib/src/backends/chroot/chroot_file.dart b/packages/file/lib/src/backends/chroot/chroot_file.dart
index 60bda56..3668ea7 100644
--- a/packages/file/lib/src/backends/chroot/chroot_file.dart
+++ b/packages/file/lib/src/backends/chroot/chroot_file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 part of file.src.backends.chroot;
 
 typedef _SetupCallback = dynamic Function();
@@ -251,7 +252,7 @@
       getDelegate(followLinks: true).openSync(mode: mode);
 
   @override
-  Stream<Uint8List> openRead([int start, int end]) =>
+  Stream<Uint8List> openRead([int? start, int? end]) =>
       getDelegate(followLinks: true).openRead(start, end).cast<Uint8List>();
 
   @override
diff --git a/packages/file/lib/src/backends/chroot/chroot_file_system.dart b/packages/file/lib/src/backends/chroot/chroot_file_system.dart
index 5e383bd..02423b7 100644
--- a/packages/file/lib/src/backends/chroot/chroot_file_system.dart
+++ b/packages/file/lib/src/backends/chroot/chroot_file_system.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 part of file.src.backends.chroot;
 
 const String _thisDir = '.';
@@ -51,10 +52,10 @@
   /// Directory in [delegate] file system that is treated as the root here.
   final String root;
 
-  String _systemTemp;
+  String? _systemTemp;
 
   /// Path to the synthetic current working directory in this file system.
-  String _cwd;
+  late String _cwd;
 
   /// Gets the root path, as seen by entities in this file system.
   String get _localRoot => delegate.path.rootPrefix(root);
@@ -255,7 +256,7 @@
   ///     the partially resolved path will be returned.
   String _resolve(
     String path, {
-    String from,
+    String? from,
     bool followLinks = true,
     _NotFoundBehavior notFound = _NotFoundBehavior.allow,
   }) {
@@ -366,14 +367,16 @@
 class _NotFoundFileStat implements FileStat {
   const _NotFoundFileStat();
 
-  @override
-  DateTime get changed => null;
+  static final DateTime _empty = DateTime(0);
 
   @override
-  DateTime get modified => null;
+  DateTime get changed => _empty;
 
   @override
-  DateTime get accessed => null;
+  DateTime get modified => _empty;
+
+  @override
+  DateTime get accessed => _empty;
 
   @override
   FileSystemEntityType get type => FileSystemEntityType.notFound;
diff --git a/packages/file/lib/src/backends/chroot/chroot_file_system_entity.dart b/packages/file/lib/src/backends/chroot/chroot_file_system_entity.dart
index 8e859ac..d9e726d 100644
--- a/packages/file/lib/src/backends/chroot/chroot_file_system_entity.dart
+++ b/packages/file/lib/src/backends/chroot/chroot_file_system_entity.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 part of file.src.backends.chroot;
 
 abstract class _ChrootFileSystemEntity<T extends FileSystemEntity,
diff --git a/packages/file/lib/src/backends/chroot/chroot_link.dart b/packages/file/lib/src/backends/chroot/chroot_link.dart
index acbeda6..1eb7497 100644
--- a/packages/file/lib/src/backends/chroot/chroot_link.dart
+++ b/packages/file/lib/src/backends/chroot/chroot_link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 part of file.src.backends.chroot;
 
 class _ChrootLink extends _ChrootFileSystemEntity<Link, io.Link>
diff --git a/packages/file/lib/src/backends/local.dart b/packages/file/lib/src/backends/local.dart
index 1e92241..eef8548 100644
--- a/packages/file/lib/src/backends/local.dart
+++ b/packages/file/lib/src/backends/local.dart
@@ -2,4 +2,5 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 export 'local/local_file_system.dart' show LocalFileSystem;
diff --git a/packages/file/lib/src/backends/local/local_directory.dart b/packages/file/lib/src/backends/local/local_directory.dart
index ecb55cf..15030c6 100644
--- a/packages/file/lib/src/backends/local/local_directory.dart
+++ b/packages/file/lib/src/backends/local/local_directory.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/common.dart' as common;
 import 'package:file/src/forwarding.dart';
 import 'package:file/src/io.dart' as io;
diff --git a/packages/file/lib/src/backends/local/local_file.dart b/packages/file/lib/src/backends/local/local_file.dart
index e7ed49d..239f46e 100644
--- a/packages/file/lib/src/backends/local/local_file.dart
+++ b/packages/file/lib/src/backends/local/local_file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/forwarding.dart';
 import 'package:file/src/io.dart' as io;
 import 'package:file/file.dart';
diff --git a/packages/file/lib/src/backends/local/local_file_system.dart b/packages/file/lib/src/backends/local/local_file_system.dart
index 069c436..4dc4451 100644
--- a/packages/file/lib/src/backends/local/local_file_system.dart
+++ b/packages/file/lib/src/backends/local/local_file_system.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/src/io.dart' as io;
diff --git a/packages/file/lib/src/backends/local/local_file_system_entity.dart b/packages/file/lib/src/backends/local/local_file_system_entity.dart
index acfe761..fc4adfc 100644
--- a/packages/file/lib/src/backends/local/local_file_system_entity.dart
+++ b/packages/file/lib/src/backends/local/local_file_system_entity.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/forwarding.dart';
 import 'package:file/src/io.dart' as io;
 import 'package:file/file.dart';
diff --git a/packages/file/lib/src/backends/local/local_link.dart b/packages/file/lib/src/backends/local/local_link.dart
index 46c3190..2f8956b 100644
--- a/packages/file/lib/src/backends/local/local_link.dart
+++ b/packages/file/lib/src/backends/local/local_link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/forwarding.dart';
 import 'package:file/src/io.dart' as io;
 import 'package:file/file.dart';
diff --git a/packages/file/lib/src/backends/memory.dart b/packages/file/lib/src/backends/memory.dart
index 428bc54..8ec1612 100644
--- a/packages/file/lib/src/backends/memory.dart
+++ b/packages/file/lib/src/backends/memory.dart
@@ -2,5 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 export 'memory/memory_file_system.dart' show MemoryFileSystem;
 export 'memory/style.dart' show FileSystemStyle, StyleableFileSystem;
diff --git a/packages/file/lib/src/backends/memory/clock.dart b/packages/file/lib/src/backends/memory/clock.dart
index 12549aa..d078057 100644
--- a/packages/file/lib/src/backends/memory/clock.dart
+++ b/packages/file/lib/src/backends/memory/clock.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// Interface describing clocks used by the [MemoryFileSystem].
 ///
 /// The [MemoryFileSystem] uses a clock to determine the modification times of
@@ -39,7 +41,7 @@
 
 class _MonotonicTestClock extends Clock {
   _MonotonicTestClock({
-    DateTime start,
+    DateTime? start,
   }) : _current = start ?? DateTime(2000);
 
   DateTime _current;
diff --git a/packages/file/lib/src/backends/memory/common.dart b/packages/file/lib/src/backends/memory/common.dart
index d9d8f5c..f8f43de 100644
--- a/packages/file/lib/src/backends/memory/common.dart
+++ b/packages/file/lib/src/backends/memory/common.dart
@@ -2,13 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/common.dart' as common;
 
 /// Generates a path to use in error messages.
 typedef PathGenerator = dynamic Function();
 
 /// Throws a `FileSystemException` if [object] is null.
-void checkExists(Object object, PathGenerator path) {
+void checkExists(Object? object, PathGenerator path) {
   if (object == null) {
     throw common.noSuchFileOrDirectory(path() as String);
   }
diff --git a/packages/file/lib/src/backends/memory/memory_directory.dart b/packages/file/lib/src/backends/memory/memory_directory.dart
index 688e0df..8285a2a 100644
--- a/packages/file/lib/src/backends/memory/memory_directory.dart
+++ b/packages/file/lib/src/backends/memory/memory_directory.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/file.dart';
@@ -39,7 +40,7 @@
   }
 
   @override
-  bool existsSync() => backingOrNull?.stat?.type == expectedType;
+  bool existsSync() => backingOrNull?.stat.type == expectedType;
 
   @override
   Future<Directory> create({bool recursive = false}) async {
@@ -49,7 +50,7 @@
 
   @override
   void createSync({bool recursive = false}) {
-    Node node = internalCreateSync(
+    Node? node = internalCreateSync(
       followTailLink: true,
       visitLinks: true,
       createChild: (DirectoryNode parent, bool isFinalSegment) {
@@ -59,17 +60,18 @@
         return null;
       },
     );
-    if (node.type != expectedType) {
+    if (node?.type != expectedType) {
       // There was an existing non-directory node at this object's path
       throw common.notADirectory(path);
     }
   }
 
   @override
-  Future<Directory> createTemp([String prefix]) async => createTempSync(prefix);
+  Future<Directory> createTemp([String? prefix]) async =>
+      createTempSync(prefix);
 
   @override
-  Directory createTempSync([String prefix]) {
+  Directory createTempSync([String? prefix]) {
     prefix = (prefix ?? '') + 'rand';
     String fullPath = fileSystem.path.join(path, prefix);
     String dirname = fileSystem.path.dirname(fullPath);
@@ -142,7 +144,7 @@
         while (followLinks &&
             utils.isLink(child) &&
             breadcrumbs.add(child as LinkNode)) {
-          Node referent = (child as LinkNode).referentOrNull;
+          Node? referent = child.referentOrNull;
           if (referent != null) {
             child = referent;
           }
diff --git a/packages/file/lib/src/backends/memory/memory_file.dart b/packages/file/lib/src/backends/memory/memory_file.dart
index 3d7b8b3..a1315cd 100644
--- a/packages/file/lib/src/backends/memory/memory_file.dart
+++ b/packages/file/lib/src/backends/memory/memory_file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 import 'dart:convert';
 import 'dart:math' as math show min;
@@ -25,7 +26,7 @@
       : super(fileSystem, path);
 
   FileNode get _resolvedBackingOrCreate {
-    Node node = backingOrNull;
+    Node? node = backingOrNull;
     if (node == null) {
       node = _doCreate();
     } else {
@@ -41,7 +42,7 @@
   io.FileSystemEntityType get expectedType => io.FileSystemEntityType.file;
 
   @override
-  bool existsSync() => backingOrNull?.stat?.type == expectedType;
+  bool existsSync() => backingOrNull?.stat.type == expectedType;
 
   @override
   Future<File> create({bool recursive = false}) async {
@@ -54,8 +55,8 @@
     _doCreate(recursive: recursive);
   }
 
-  Node _doCreate({bool recursive = false}) {
-    Node node = internalCreateSync(
+  Node? _doCreate({bool recursive = false}) {
+    Node? node = internalCreateSync(
       followTailLink: true,
       createChild: (DirectoryNode parent, bool isFinalSegment) {
         if (isFinalSegment) {
@@ -66,9 +67,9 @@
         return null;
       },
     );
-    if (node.type != expectedType) {
+    if (node?.type != expectedType) {
       // There was an existing non-file entity at this object's path
-      assert(node.type == FileSystemEntityType.directory);
+      assert(node?.type == FileSystemEntityType.directory);
       throw common.isADirectory(path);
     }
     return node;
@@ -102,7 +103,7 @@
       segmentVisitor: (
         DirectoryNode parent,
         String childName,
-        Node child,
+        Node? child,
         int currentSegment,
         int finalSegment,
       ) {
@@ -188,7 +189,7 @@
   }
 
   @override
-  Stream<Uint8List> openRead([int start, int end]) {
+  Stream<Uint8List> openRead([int? start, int? end]) {
     try {
       FileNode node = resolvedBacking as FileNode;
       Uint8List content = node.content;
@@ -317,8 +318,8 @@
     io.FileMode mode,
     Encoding encoding,
   ) {
-    FileNode node;
-    Exception deferredException;
+    late FileNode node;
+    Exception? deferredException;
 
     // Resolve the backing immediately to ensure that the [FileNode] we write
     // to is the same as when [openWrite] was called.  This can matter if the
@@ -341,15 +342,12 @@
     return _FileSink._(future, encoding);
   }
 
-  _FileSink._(this._node, this.encoding) {
-    _pendingWrites = _node;
-  }
+  _FileSink._(Future<FileNode> _node, this.encoding) : _pendingWrites = _node;
 
-  final Future<FileNode> _node;
   final Completer<void> _completer = Completer<void>();
 
   Future<FileNode> _pendingWrites;
-  Completer<void> _streamCompleter;
+  Completer<void>? _streamCompleter;
   bool _isClosed = false;
 
   @override
@@ -368,13 +366,13 @@
   }
 
   @override
-  void write(Object obj) => add(encoding.encode(obj?.toString() ?? 'null'));
+  void write(Object? obj) => add(encoding.encode(obj?.toString() ?? 'null'));
 
   @override
   void writeAll(Iterable<dynamic> objects, [String separator = '']) {
     bool firstIter = true;
     for (dynamic obj in objects) {
-      if (!firstIter && separator != null) {
+      if (!firstIter) {
         write(separator);
       }
       firstIter = false;
@@ -383,7 +381,7 @@
   }
 
   @override
-  void writeln([Object obj = '']) {
+  void writeln([Object? obj = '']) {
     write(obj);
     write('\n');
   }
@@ -392,7 +390,7 @@
   void writeCharCode(int charCode) => write(String.fromCharCode(charCode));
 
   @override
-  void addError(dynamic error, [StackTrace stackTrace]) {
+  void addError(Object error, [StackTrace? stackTrace]) {
     _checkNotStreaming();
     _completer.completeError(error, stackTrace);
   }
@@ -402,20 +400,20 @@
     _checkNotStreaming();
     _streamCompleter = Completer<void>();
     void finish() {
-      _streamCompleter.complete();
+      _streamCompleter!.complete();
       _streamCompleter = null;
     }
 
     stream.listen(
       (List<int> data) => _addData(data),
       cancelOnError: true,
-      onError: (dynamic error, StackTrace stackTrace) {
+      onError: (Object error, StackTrace stackTrace) {
         _completer.completeError(error, stackTrace);
         finish();
       },
       onDone: finish,
     );
-    return _streamCompleter.future;
+    return _streamCompleter!.future;
   }
 
   @override
@@ -431,7 +429,7 @@
       _isClosed = true;
       _pendingWrites.then(
         (_) => _completer.complete(),
-        onError: (dynamic error, StackTrace stackTrace) =>
+        onError: (Object error, StackTrace stackTrace) =>
             _completer.completeError(error, stackTrace),
       );
     }
diff --git a/packages/file/lib/src/backends/memory/memory_file_stat.dart b/packages/file/lib/src/backends/memory/memory_file_stat.dart
index deadb8a..0e158cc 100644
--- a/packages/file/lib/src/backends/memory/memory_file_stat.dart
+++ b/packages/file/lib/src/backends/memory/memory_file_stat.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/src/io.dart' as io;
 
 /// Internal implementation of [io.FileStat].
@@ -16,16 +17,16 @@
     this.size,
   );
 
-  const MemoryFileStat._internalNotFound()
-      : changed = null,
-        modified = null,
-        accessed = null,
+  MemoryFileStat._internalNotFound()
+      : changed = DateTime(0),
+        modified = DateTime(0),
+        accessed = DateTime(0),
         type = io.FileSystemEntityType.notFound,
         mode = 0,
         size = -1;
 
   /// Shared instance representing a non-existent entity.
-  static const MemoryFileStat notFound = MemoryFileStat._internalNotFound();
+  static final MemoryFileStat notFound = MemoryFileStat._internalNotFound();
 
   @override
   final DateTime changed;
diff --git a/packages/file/lib/src/backends/memory/memory_file_system.dart b/packages/file/lib/src/backends/memory/memory_file_system.dart
index 0451326..679f1fc 100644
--- a/packages/file/lib/src/backends/memory/memory_file_system.dart
+++ b/packages/file/lib/src/backends/memory/memory_file_system.dart
@@ -2,11 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/file.dart';
 import 'package:file/src/io.dart' as io;
-import 'package:meta/meta.dart';
 import 'package:path/path.dart' as p;
 
 import 'clock.dart';
@@ -74,16 +74,15 @@
     implements MemoryFileSystem, NodeBasedFileSystem {
   _MemoryFileSystem({
     this.style = FileSystemStyle.posix,
-    @required this.clock,
-  })  : assert(style != null),
-        assert(clock != null) {
-    _root = RootNode(this);
+    required this.clock,
+  }) {
     _context = style.contextFor(style.root);
+    _root = RootNode(this);
   }
 
-  RootNode _root;
-  String _systemTemp;
-  p.Context _context;
+  RootNode? _root;
+  String? _systemTemp;
+  late p.Context _context;
 
   @override
   final Clock clock;
@@ -92,7 +91,7 @@
   final FileSystemStyle style;
 
   @override
-  RootNode get root => _root;
+  RootNode? get root => _root;
 
   @override
   String get cwd => _context.current;
@@ -133,9 +132,9 @@
     }
 
     value = directory(value).resolveSymbolicLinksSync();
-    Node node = findNode(value);
+    Node? node = findNode(value);
     checkExists(node, () => value);
-    utils.checkIsDir(node, () => value);
+    utils.checkIsDir(node!, () => value);
     assert(_context.isAbsolute(value));
     _context = style.contextFor(value);
   }
@@ -158,9 +157,9 @@
 
   @override
   bool identicalSync(String path1, String path2) {
-    Node node1 = findNode(path1);
+    Node? node1 = findNode(path1);
     checkExists(node1, () => path1);
-    Node node2 = findNode(path2);
+    Node? node2 = findNode(path2);
     checkExists(node2, () => path2);
     return node1 != null && node1 == node2;
   }
@@ -177,7 +176,7 @@
 
   @override
   io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) {
-    Node node;
+    Node? node;
     try {
       node = findNode(path, followTailLink: followLinks);
     } on io.FileSystemException {
@@ -195,18 +194,14 @@
   DirectoryNode get _current => findNode(cwd) as DirectoryNode;
 
   @override
-  Node findNode(
+  Node? findNode(
     String path, {
-    Node reference,
-    SegmentVisitor segmentVisitor,
+    Node? reference,
+    SegmentVisitor? segmentVisitor,
     bool visitLinks = false,
-    List<String> pathWithSymlinks,
+    List<String>? pathWithSymlinks,
     bool followTailLink = false,
   }) {
-    if (path == null) {
-      throw ArgumentError.notNull('path');
-    }
-
     if (_context.isAbsolute(path)) {
       reference = _root;
       path = path.substring(style.drive.length);
@@ -216,8 +211,8 @@
 
     List<String> parts = path.split(style.separator)
       ..removeWhere(utils.isEmpty);
-    DirectoryNode directory = reference.directory;
-    Node child = directory;
+    DirectoryNode? directory = reference?.directory;
+    Node? child = directory;
 
     int finalSegment = parts.length - 1;
     for (int i = 0; i <= finalSegment; i++) {
@@ -229,11 +224,11 @@
           child = directory;
           break;
         case _parentDir:
-          child = directory.parent;
-          directory = directory.parent;
+          child = directory?.parent;
+          directory = directory?.parent;
           break;
         default:
-          child = directory.children[basename];
+          child = directory?.children[basename];
       }
 
       if (pathWithSymlinks != null) {
@@ -246,7 +241,8 @@
       if (utils.isLink(child) && (i < finalSegment || followTailLink)) {
         if (visitLinks || segmentVisitor == null) {
           if (segmentVisitor != null) {
-            child = segmentVisitor(directory, basename, child, i, finalSegment);
+            child =
+                segmentVisitor(directory!, basename, child, i, finalSegment);
           }
           child = utils.resolveLinks(child as LinkNode, subpath,
               ledger: pathWithSymlinks);
@@ -255,18 +251,18 @@
             child as LinkNode,
             subpath,
             ledger: pathWithSymlinks,
-            tailVisitor: (DirectoryNode parent, String childName, Node child) {
+            tailVisitor: (DirectoryNode parent, String childName, Node? child) {
               return segmentVisitor(parent, childName, child, i, finalSegment);
             },
           );
         }
       } else if (segmentVisitor != null) {
-        child = segmentVisitor(directory, basename, child, i, finalSegment);
+        child = segmentVisitor(directory!, basename, child, i, finalSegment);
       }
 
       if (i < finalSegment) {
         checkExists(child, subpath);
-        utils.checkIsDir(child, subpath);
+        utils.checkIsDir(child!, subpath);
         directory = child as DirectoryNode;
       }
     }
diff --git a/packages/file/lib/src/backends/memory/memory_file_system_entity.dart b/packages/file/lib/src/backends/memory/memory_file_system_entity.dart
index 3ff5ba9..fa0b0a6 100644
--- a/packages/file/lib/src/backends/memory/memory_file_system_entity.dart
+++ b/packages/file/lib/src/backends/memory/memory_file_system_entity.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/file.dart';
@@ -47,7 +48,7 @@
   /// Gets the node that backs this file system entity, or null if this
   /// entity does not exist.
   @protected
-  Node get backingOrNull {
+  Node? get backingOrNull {
     try {
       return fileSystem.findNode(path);
     } on io.FileSystemException {
@@ -61,9 +62,9 @@
   /// The type of the node is not guaranteed to match [expectedType].
   @protected
   Node get backing {
-    Node node = fileSystem.findNode(path);
+    Node? node = fileSystem.findNode(path);
     checkExists(node, () => path);
-    return node;
+    return node!;
   }
 
   /// Gets the node that backs this file system entity, or if that node is
@@ -112,7 +113,7 @@
     if (isAbsolute) {
       ledger.add(fileSystem.style.drive);
     }
-    Node node = fileSystem.findNode(path,
+    Node? node = fileSystem.findNode(path,
         pathWithSymlinks: ledger, followTailLink: true);
     checkExists(node, () => path);
     String resolved = ledger.join(fileSystem.path.separator);
@@ -181,8 +182,8 @@
   /// If [followTailLink] is true and the result node is a link, this will
   /// resolve it to its target prior to returning it.
   @protected
-  Node internalCreateSync({
-    Node createChild(DirectoryNode parent, bool isFinalSegment),
+  Node? internalCreateSync({
+    required Node? createChild(DirectoryNode parent, bool isFinalSegment),
     bool followTailLink = false,
     bool visitLinks = false,
   }) {
@@ -193,7 +194,7 @@
       segmentVisitor: (
         DirectoryNode parent,
         String childName,
-        Node child,
+        Node? child,
         int currentSegment,
         int finalSegment,
       ) {
@@ -238,9 +239,9 @@
   @protected
   FileSystemEntity internalRenameSync<T extends Node>(
     String newPath, {
-    RenameOverwriteValidator<T> validateOverwriteExistingEntity,
+    RenameOverwriteValidator<T>? validateOverwriteExistingEntity,
     bool followTailLink = false,
-    utils.TypeChecker checkType,
+    utils.TypeChecker? checkType,
   }) {
     Node node = backing;
     (checkType ?? defaultCheckType)(node);
@@ -249,7 +250,7 @@
       segmentVisitor: (
         DirectoryNode parent,
         String childName,
-        Node child,
+        Node? child,
         int currentSegment,
         int finalSegment,
       ) {
@@ -286,7 +287,7 @@
   @protected
   void internalDeleteSync({
     bool recursive = false,
-    utils.TypeChecker checkType,
+    utils.TypeChecker? checkType,
   }) {
     Node node = backing;
     if (!recursive) {
diff --git a/packages/file/lib/src/backends/memory/memory_link.dart b/packages/file/lib/src/backends/memory/memory_link.dart
index b22e2fd..895cfe4 100644
--- a/packages/file/lib/src/backends/memory/memory_link.dart
+++ b/packages/file/lib/src/backends/memory/memory_link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/file.dart';
diff --git a/packages/file/lib/src/backends/memory/memory_random_access_file.dart b/packages/file/lib/src/backends/memory/memory_random_access_file.dart
index b30389f..3998cb8 100644
--- a/packages/file/lib/src/backends/memory/memory_random_access_file.dart
+++ b/packages/file/lib/src/backends/memory/memory_random_access_file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:convert';
 import 'dart:math' as math show min;
 import 'dart:typed_data';
@@ -232,11 +233,11 @@
   }
 
   @override
-  Future<int> readInto(List<int> buffer, [int start = 0, int end]) =>
+  Future<int> readInto(List<int> buffer, [int start = 0, int? end]) =>
       _asyncWrapper(() => readIntoSync(buffer, start, end));
 
   @override
-  int readIntoSync(List<int> buffer, [int start = 0, int end]) {
+  int readIntoSync(List<int> buffer, [int start = 0, int? end]) {
     _checkOpen();
     _checkAsync();
     _checkReadable('readInto');
@@ -349,14 +350,14 @@
   Future<io.RandomAccessFile> writeFrom(
     List<int> buffer, [
     int start = 0,
-    int end,
+    int? end,
   ]) async {
     await _asyncWrapper(() => writeFromSync(buffer, start, end));
     return this;
   }
 
   @override
-  void writeFromSync(List<int> buffer, [int start = 0, int end]) {
+  void writeFromSync(List<int> buffer, [int start = 0, int? end]) {
     _checkOpen();
     _checkAsync();
     _checkWritable('writeFrom');
diff --git a/packages/file/lib/src/backends/memory/node.dart b/packages/file/lib/src/backends/memory/node.dart
index e7a4029..476af38 100644
--- a/packages/file/lib/src/backends/memory/node.dart
+++ b/packages/file/lib/src/backends/memory/node.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 import 'dart:typed_data';
 
 import 'package:file/file.dart';
@@ -30,10 +32,10 @@
 ///
 /// [finalSegment] is the index of the final segment that will be walked by
 /// [NodeBasedFileSystem.findNode].
-typedef SegmentVisitor = Node Function(
+typedef SegmentVisitor = Node? Function(
   DirectoryNode parent,
   String childName,
-  Node childNode,
+  Node? childNode,
   int currentSegment,
   int finalSegment,
 );
@@ -42,7 +44,7 @@
 /// instances, rooted at a single node.
 abstract class NodeBasedFileSystem implements StyleableFileSystem {
   /// The root node.
-  RootNode get root;
+  RootNode? get root;
 
   /// The path of the current working directory.
   String get cwd;
@@ -80,7 +82,7 @@
   /// If [pathWithSymlinks] is specified, the path to the node with symbolic
   /// links explicitly broken out will be appended to the buffer. `..` and `.`
   /// path segments will *not* be resolved and are left to the caller.
-  Node findNode(
+  Node? findNode(
     String path, {
     Node reference,
     SegmentVisitor segmentVisitor,
@@ -104,14 +106,13 @@
     }
   }
 
-  DirectoryNode _parent;
+  DirectoryNode? _parent;
 
   /// Gets the directory that holds this node.
-  DirectoryNode get parent => _parent;
+  DirectoryNode get parent => _parent!;
 
   /// Reparents this node to live in the specified directory.
   set parent(DirectoryNode parent) {
-    assert(parent != null);
     DirectoryNode ancestor = parent;
     while (!ancestor.isRoot) {
       if (ancestor == this) {
@@ -132,13 +133,13 @@
   /// Returns the closest directory in the ancestry hierarchy starting with
   /// this node. For directory nodes, it returns the node itself; for other
   /// nodes, it returns the parent node.
-  DirectoryNode get directory => _parent;
+  DirectoryNode get directory => _parent!;
 
   /// Tells if this node is a root node.
   bool get isRoot => false;
 
   /// Returns the file system responsible for this node.
-  NodeBasedFileSystem get fs => _parent.fs;
+  NodeBasedFileSystem get fs => _parent!.fs;
 }
 
 /// Base class that represents the backing for those nodes that have
@@ -146,7 +147,7 @@
 /// you call [stat] on them).
 abstract class RealNode extends Node {
   /// Constructs a new [RealNode] as a child of the specified [parent].
-  RealNode(DirectoryNode parent) : super(parent) {
+  RealNode(DirectoryNode? parent) : super(parent) {
     int now = clock.now.millisecondsSinceEpoch;
     changed = now;
     modified = now;
@@ -157,13 +158,13 @@
   Clock get clock => parent.clock;
 
   /// Last changed time in milliseconds since the Epoch.
-  int changed;
+  late int changed;
 
   /// Last modified time in milliseconds since the Epoch.
-  int modified;
+  late int modified;
 
   /// Last accessed time in milliseconds since the Epoch.
-  int accessed;
+  late int accessed;
 
   /// Bitmask representing the file read/write/execute mode.
   int mode = 0x777;
@@ -192,7 +193,7 @@
 /// Class that represents the backing for an in-memory directory.
 class DirectoryNode extends RealNode {
   /// Constructs a new [DirectoryNode] as a child of the specified [parent].
-  DirectoryNode(DirectoryNode parent) : super(parent);
+  DirectoryNode(DirectoryNode? parent) : super(parent);
 
   /// Child nodes, indexed by their basename.
   final Map<String, Node> children = <String, Node>{};
@@ -211,8 +212,7 @@
 class RootNode extends DirectoryNode {
   /// Constructs a new [RootNode] tied to the specified file system.
   RootNode(this.fs)
-      : assert(fs != null),
-        assert(fs.root == null),
+      : assert(fs.root == null),
         super(null);
 
   @override
@@ -285,7 +285,7 @@
   /// Constructs a new [LinkNode] as a child of the specified [parent] and
   /// linking to the specified [target] path.
   LinkNode(DirectoryNode parent, this.target)
-      : assert(target != null && target.isNotEmpty),
+      : assert(target.isNotEmpty),
         super(parent);
 
   /// The path to which this link points.
@@ -304,15 +304,15 @@
   /// target cannot be traversed into, a [FileSystemException] will be thrown,
   /// and [tailVisitor] will not be invoked.
   Node getReferent({
-    Node tailVisitor(DirectoryNode parent, String childName, Node child),
+    Node? tailVisitor(DirectoryNode parent, String childName, Node? child)?,
   }) {
-    Node referent = fs.findNode(
+    Node? referent = fs.findNode(
       target,
       reference: this,
       segmentVisitor: (
         DirectoryNode parent,
         String childName,
-        Node child,
+        Node? child,
         int currentSegment,
         int finalSegment,
       ) {
@@ -323,12 +323,12 @@
       },
     );
     checkExists(referent, () => target);
-    return referent;
+    return referent!;
   }
 
   /// Gets the node backing for this link's target, or null if this link
   /// references a non-existent file system entity.
-  Node get referentOrNull {
+  Node? get referentOrNull {
     try {
       return getReferent();
     } on io.FileSystemException {
@@ -346,7 +346,7 @@
     }
     _reentrant = true;
     try {
-      Node node = referentOrNull;
+      Node? node = referentOrNull;
       return node == null ? MemoryFileStat.notFound : node.stat;
     } finally {
       _reentrant = false;
diff --git a/packages/file/lib/src/backends/memory/style.dart b/packages/file/lib/src/backends/memory/style.dart
index 701c9d0..945afe8 100644
--- a/packages/file/lib/src/backends/memory/style.dart
+++ b/packages/file/lib/src/backends/memory/style.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/file.dart';
 import 'package:path/path.dart' as p;
 
diff --git a/packages/file/lib/src/backends/memory/utils.dart b/packages/file/lib/src/backends/memory/utils.dart
index de1b6ae..e27a82a 100644
--- a/packages/file/lib/src/backends/memory/utils.dart
+++ b/packages/file/lib/src/backends/memory/utils.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'package:file/file.dart';
 import 'package:file/src/common.dart' as common;
 import 'package:file/src/io.dart' as io;
@@ -10,13 +11,13 @@
 import 'node.dart';
 
 /// Checks if `node.type` returns [io.FileSystemEntityType.FILE].
-bool isFile(Node node) => node?.type == io.FileSystemEntityType.file;
+bool isFile(Node? node) => node?.type == io.FileSystemEntityType.file;
 
 /// Checks if `node.type` returns [io.FileSystemEntityType.DIRECTORY].
-bool isDirectory(Node node) => node?.type == io.FileSystemEntityType.directory;
+bool isDirectory(Node? node) => node?.type == io.FileSystemEntityType.directory;
 
 /// Checks if `node.type` returns [io.FileSystemEntityType.LINK].
-bool isLink(Node node) => node?.type == io.FileSystemEntityType.link;
+bool isLink(Node? node) => node?.type == io.FileSystemEntityType.link;
 
 /// Validator function that is expected to throw a [FileSystemException] if
 /// the node does not represent the type that is expected in any given context.
@@ -81,8 +82,8 @@
 Node resolveLinks(
   LinkNode link,
   PathGenerator path, {
-  List<String> ledger,
-  Node tailVisitor(DirectoryNode parent, String childName, Node child),
+  List<String>? ledger,
+  Node? tailVisitor(DirectoryNode parent, String childName, Node? child)?,
 }) {
   // Record a breadcrumb trail to guard against symlink loops.
   Set<LinkNode> breadcrumbs = Set<LinkNode>();
@@ -102,7 +103,7 @@
       ledger.addAll(link.target.split(link.fs.path.separator));
     }
     node = link.getReferent(
-      tailVisitor: (DirectoryNode parent, String childName, Node child) {
+      tailVisitor: (DirectoryNode parent, String childName, Node? child) {
         if (tailVisitor != null && !isLink(child)) {
           // Only invoke [tailListener] on the final resolution pass.
           child = tailVisitor(parent, childName, child);
diff --git a/packages/file/lib/src/backends/record_replay/codecs.dart b/packages/file/lib/src/backends/record_replay/codecs.dart
deleted file mode 100644
index 01f4abe..0000000
--- a/packages/file/lib/src/backends/record_replay/codecs.dart
+++ /dev/null
@@ -1,774 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io' show systemEncoding;
-import 'dart:typed_data';
-
-import 'package:file/file.dart';
-import 'package:path/path.dart' as path;
-
-import 'common.dart';
-import 'errors.dart';
-import 'events.dart';
-import 'replay_directory.dart';
-import 'replay_file.dart';
-import 'replay_file_stat.dart';
-import 'replay_file_system.dart';
-import 'replay_io_sink.dart';
-import 'replay_link.dart';
-import 'replay_random_access_file.dart';
-import 'result_reference.dart';
-
-/// Encodes an arbitrary [object] into a JSON-ready representation (a number,
-/// boolean, string, null, list, or map).
-///
-/// Returns a value suitable for conversion into JSON using [JsonEncoder]
-/// without the need for a `toEncodable` argument.
-dynamic encode(dynamic object) => const _GenericEncoder().convert(object);
-
-typedef _ConverterDelegate<S, T> = T Function(S input);
-
-class _ForwardingConverter<S, T> extends Converter<S, T> {
-  const _ForwardingConverter(this._delegate);
-
-  final _ConverterDelegate<S, T> _delegate;
-
-  @override
-  T convert(S input) => _delegate(input);
-}
-
-class _GenericEncoder extends Converter<dynamic, dynamic> {
-  const _GenericEncoder();
-
-  /// Known encoders. Types not covered here will be encoded as a [String]
-  /// whose value is the runtime type of the object being encoded.
-  ///
-  /// When encoding an object, we will walk this map in insertion order looking
-  /// for a matching encoder. Thus, when there are two encoders that match an
-  /// object, the first one will win.
-  static const Map<TypeMatcher<dynamic>, Converter<Object, Object>> _encoders =
-      <TypeMatcher<dynamic>, Converter<Object, Object>>{
-    TypeMatcher<num>(): Passthrough<num>(),
-    TypeMatcher<bool>(): Passthrough<bool>(),
-    TypeMatcher<String>(): Passthrough<String>(),
-    TypeMatcher<Null>(): Passthrough<Null>(),
-    TypeMatcher<Iterable<dynamic>>(): _IterableEncoder(),
-    TypeMatcher<Map<dynamic, dynamic>>(): _MapEncoder(),
-    TypeMatcher<Symbol>(): _SymbolEncoder(),
-    TypeMatcher<DateTime>(): DateTimeCodec.serialize,
-    TypeMatcher<Uri>(): UriCodec.serialize,
-    TypeMatcher<path.Context>(): PathContextCodec.serialize,
-    TypeMatcher<ResultReference<dynamic>>(): _ResultEncoder(),
-    TypeMatcher<LiveInvocationEvent<dynamic>>(): _EventEncoder(),
-    TypeMatcher<ReplayAware>(): _ReplayAwareEncoder(),
-    TypeMatcher<Encoding>(): EncodingCodec.serialize,
-    TypeMatcher<FileMode>(): _FileModeEncoder(),
-    TypeMatcher<FileStat>(): FileStatCodec.serialize,
-    TypeMatcher<FileSystemEntityType>(): EntityTypeCodec.serialize,
-    TypeMatcher<FileSystemEvent>(): FileSystemEventCodec.serialize,
-    TypeMatcher<FileSystemException>(): _FSExceptionCodec.serialize,
-    TypeMatcher<OSError>(): _OSErrorCodec.serialize,
-    TypeMatcher<ArgumentError>(): _ArgumentErrorCodec.serialize,
-    TypeMatcher<NoSuchMethodError>(): _NoSuchMethodErrorCodec.serialize,
-  };
-
-  @override
-  dynamic convert(dynamic input) {
-    for (TypeMatcher<dynamic> matcher in _encoders.keys) {
-      if (matcher.matches(input)) {
-        return _encoders[matcher].convert(input);
-      }
-    }
-    return input.runtimeType.toString();
-  }
-}
-
-/// A trivial conversion turning a Sink<List<String>> into a
-/// Sink<String>
-class _StringSinkWrapper implements Sink<String> {
-  _StringSinkWrapper(this._sink);
-
-  final Sink<List<String>> _sink;
-
-  @override
-  void add(String s) => _sink.add(<String>[s]);
-
-  @override
-  void close() => _sink.close();
-}
-
-/// A [Converter] version of the dart:convert [LineSplitter] (which in
-/// 2.0 no longer implements the [Converter] interface).
-class LineSplitterConverter extends Converter<String, List<String>> {
-  /// Creates a new [LineSplitterConverter]
-  const LineSplitterConverter();
-
-  LineSplitter get _splitter => const LineSplitter();
-
-  @override
-  List<String> convert(String input) => _splitter.convert(input);
-  @override
-  StringConversionSink startChunkedConversion(Sink<List<String>> sink) =>
-      _splitter.startChunkedConversion(_StringSinkWrapper(sink));
-}
-
-/// Converter that leaves an object untouched.
-class Passthrough<T> extends Converter<T, T> {
-  /// Creates a new [Passthrough].
-  const Passthrough();
-
-  @override
-  T convert(T input) => input;
-}
-
-class _IterableEncoder extends Converter<Iterable<dynamic>, List<dynamic>> {
-  const _IterableEncoder();
-
-  @override
-  List<dynamic> convert(Iterable<dynamic> input) {
-    _GenericEncoder generic = const _GenericEncoder();
-    List<dynamic> encoded = <dynamic>[];
-    for (Object element in input) {
-      encoded.add(generic.convert(element));
-    }
-    return encoded;
-  }
-}
-
-class _MapEncoder
-    extends Converter<Map<dynamic, dynamic>, Map<String, dynamic>> {
-  const _MapEncoder();
-
-  @override
-  Map<String, dynamic> convert(Map<dynamic, dynamic> input) {
-    _GenericEncoder generic = const _GenericEncoder();
-    Map<String, dynamic> encoded = <String, dynamic>{};
-    for (dynamic key in input.keys) {
-      String encodedKey = generic.convert(key) as String;
-      encoded[encodedKey] = generic.convert(input[key]);
-    }
-    return encoded;
-  }
-}
-
-class _SymbolEncoder extends Converter<Symbol, String> {
-  const _SymbolEncoder();
-
-  @override
-  String convert(Symbol input) => getSymbolName(input);
-}
-
-/// A [DateTimeCodec] serializes and deserializes [DateTime] instances.
-class DateTimeCodec extends Codec<DateTime, int> {
-  /// Creates a new [DateTimeCodec].
-  const DateTimeCodec();
-
-  static int _encode(DateTime input) => input?.millisecondsSinceEpoch;
-
-  static DateTime _decode(int input) {
-    return input == null ? null : DateTime.fromMillisecondsSinceEpoch(input);
-  }
-
-  /// Converter that serializes [DateTime] instances.
-  static const Converter<DateTime, int> serialize =
-      _ForwardingConverter<DateTime, int>(_encode);
-
-  /// Converter that deserializes [DateTime] instances.
-  static const Converter<int, DateTime> deserialize =
-      _ForwardingConverter<int, DateTime>(_decode);
-
-  @override
-  Converter<DateTime, int> get encoder => serialize;
-
-  @override
-  Converter<int, DateTime> get decoder => deserialize;
-}
-
-/// A [UriCodec] serializes and deserializes [Uri] instances.
-class UriCodec extends Codec<Uri, String> {
-  /// Creates a new [UriCodec].
-  const UriCodec();
-
-  static String _encode(Uri input) => input.toString();
-
-  static Uri _decode(String input) => Uri.parse(input);
-
-  /// Converter that serializes [Uri] instances.
-  static const Converter<Uri, String> serialize =
-      _ForwardingConverter<Uri, String>(_encode);
-
-  /// Converter that deserializes [Uri] instances.
-  static const Converter<String, Uri> deserialize =
-      _ForwardingConverter<String, Uri>(_decode);
-
-  @override
-  Converter<Uri, String> get encoder => serialize;
-
-  @override
-  Converter<String, Uri> get decoder => deserialize;
-}
-
-/// A [PathContextCodec] serializes and deserializes [path.Context] instances.
-class PathContextCodec extends Codec<path.Context, Map<String, dynamic>> {
-  /// Creates a new [PathContextCodec].
-  const PathContextCodec();
-
-  static Map<String, dynamic> _encode(path.Context input) {
-    return <String, String>{
-      'style': input.style.name,
-      'cwd': input.current,
-    };
-  }
-
-  static path.Context _decode(Map<String, dynamic> input) {
-    return path.Context(
-      style: <String, path.Style>{
-        'posix': path.Style.posix,
-        'windows': path.Style.windows,
-        'url': path.Style.url,
-      }[input['style']],
-      current: input['cwd'] as String,
-    );
-  }
-
-  /// Converter that serializes [path.Context] instances.
-  static const Converter<path.Context, Map<String, dynamic>> serialize =
-      _ForwardingConverter<path.Context, Map<String, dynamic>>(_encode);
-
-  /// Converter that deserializes [path.Context] instances.
-  static const Converter<Map<String, dynamic>, path.Context> deserialize =
-      _ForwardingConverter<Map<String, dynamic>, path.Context>(_decode);
-
-  @override
-  Converter<path.Context, Map<String, dynamic>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, dynamic>, path.Context> get decoder => deserialize;
-}
-
-class _ResultEncoder extends Converter<ResultReference<dynamic>, Object> {
-  const _ResultEncoder();
-
-  @override
-  Object convert(ResultReference<dynamic> input) => input.serializedValue;
-}
-
-class _EventEncoder
-    extends Converter<LiveInvocationEvent<dynamic>, Map<String, Object>> {
-  const _EventEncoder();
-
-  @override
-  Map<String, Object> convert(LiveInvocationEvent<dynamic> input) {
-    return input.serialize();
-  }
-}
-
-class _ReplayAwareEncoder extends Converter<ReplayAware, String> {
-  const _ReplayAwareEncoder();
-
-  @override
-  String convert(ReplayAware input) => input.identifier;
-}
-
-/// An [EncodingCodec] serializes and deserializes [Encoding] instances.
-class EncodingCodec extends Codec<Encoding, String> {
-  /// Creates a new [EncodingCodec].
-  const EncodingCodec();
-
-  static String _encode(Encoding input) => input.name;
-
-  static Encoding _decode(String input) {
-    if (input == 'system') {
-      return systemEncoding;
-    } else if (input != null) {
-      return Encoding.getByName(input);
-    }
-    return null;
-  }
-
-  /// Converter that serializes [Encoding] instances.
-  static const Converter<Encoding, String> serialize =
-      _ForwardingConverter<Encoding, String>(_encode);
-
-  /// Converter that deserializes [Encoding] instances.
-  static const Converter<String, Encoding> deserialize =
-      _ForwardingConverter<String, Encoding>(_decode);
-
-  @override
-  Converter<Encoding, String> get encoder => serialize;
-
-  @override
-  Converter<String, Encoding> get decoder => deserialize;
-}
-
-class _FileModeEncoder extends Converter<FileMode, String> {
-  const _FileModeEncoder();
-
-  @override
-  String convert(FileMode input) {
-    switch (input) {
-      case FileMode.read:
-        return 'READ';
-      case FileMode.write:
-        return 'WRITE';
-      case FileMode.append:
-        return 'APPEND';
-      case FileMode.writeOnly:
-        return 'WRITE_ONLY';
-      case FileMode.writeOnlyAppend:
-        return 'WRITE_ONLY_APPEND';
-    }
-    throw ArgumentError('Invalid value: $input');
-  }
-}
-
-/// An [FileStatCodec] serializes and deserializes [FileStat] instances.
-class FileStatCodec extends Codec<FileStat, Map<String, Object>> {
-  /// Creates a new [FileStatCodec].
-  const FileStatCodec();
-
-  static Map<String, Object> _encode(FileStat input) {
-    return <String, dynamic>{
-      'changed': const DateTimeCodec().encode(input.changed),
-      'modified': const DateTimeCodec().encode(input.modified),
-      'accessed': const DateTimeCodec().encode(input.accessed),
-      'type': const EntityTypeCodec().encode(input.type),
-      'mode': input.mode,
-      'size': input.size,
-      'modeString': input.modeString(),
-    };
-  }
-
-  static FileStat _decode(Map<String, Object> input) => ReplayFileStat(input);
-
-  /// Converter that serializes [FileStat] instances.
-  static const Converter<FileStat, Map<String, Object>> serialize =
-      _ForwardingConverter<FileStat, Map<String, Object>>(_encode);
-
-  /// Converter that deserializes [FileStat] instances.
-  static const Converter<Map<String, Object>, FileStat> deserialize =
-      _ForwardingConverter<Map<String, Object>, FileStat>(_decode);
-
-  @override
-  Converter<FileStat, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, FileStat> get decoder => deserialize;
-}
-
-/// An [EntityTypeCodec] serializes and deserializes [FileSystemEntity]
-/// instances.
-class EntityTypeCodec extends Codec<FileSystemEntityType, String> {
-  /// Creates a new [EntityTypeCodec].
-  const EntityTypeCodec();
-
-  static String _encode(FileSystemEntityType input) => input.toString();
-
-  static FileSystemEntityType _decode(String input) {
-    return const <String, FileSystemEntityType>{
-      'file': FileSystemEntityType.file,
-      'directory': FileSystemEntityType.directory,
-      'link': FileSystemEntityType.link,
-      'notFound': FileSystemEntityType.notFound,
-    }[input];
-  }
-
-  /// Converter that serializes [FileSystemEntityType] instances.
-  static const Converter<FileSystemEntityType, String> serialize =
-      _ForwardingConverter<FileSystemEntityType, String>(_encode);
-
-  /// Converter that deserializes [FileSystemEntityType] instances.
-  static const Converter<String, FileSystemEntityType> deserialize =
-      _ForwardingConverter<String, FileSystemEntityType>(_decode);
-
-  @override
-  Converter<FileSystemEntityType, String> get encoder => serialize;
-
-  @override
-  Converter<String, FileSystemEntityType> get decoder => deserialize;
-}
-
-/// A [FileSystemEventCodec] serializes and deserializes [FileSystemEvent]
-/// instances.
-class FileSystemEventCodec extends Codec<FileSystemEvent, Map<String, Object>> {
-  /// Creates a new [FileSystemEventCodec].
-  const FileSystemEventCodec();
-
-  static Map<String, Object> _encode(FileSystemEvent input) {
-    return <String, Object>{
-      'type': input.type,
-      'path': input.path,
-      'isDirectory': input.isDirectory,
-    };
-  }
-
-  static FileSystemEvent _decode(Map<String, Object> input) =>
-      _FileSystemEvent(input);
-
-  /// Converter that serializes [FileSystemEvent] instances.
-  static const Converter<FileSystemEvent, Map<String, Object>> serialize =
-      _ForwardingConverter<FileSystemEvent, Map<String, Object>>(_encode);
-
-  /// Converter that deserializes [FileSystemEvent] instances.
-  static const Converter<Map<String, Object>, FileSystemEvent> deserialize =
-      _ForwardingConverter<Map<String, Object>, FileSystemEvent>(_decode);
-
-  @override
-  Converter<FileSystemEvent, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, FileSystemEvent> get decoder => deserialize;
-}
-
-class _FileSystemEvent implements FileSystemEvent {
-  const _FileSystemEvent(this._data);
-
-  final Map<String, Object> _data;
-
-  @override
-  int get type => _data['type'] as int;
-
-  @override
-  String get path => _data['path'] as String;
-
-  @override
-  bool get isDirectory => _data['isDirectory'] as bool;
-}
-
-/// Converts an object into a [Future] that completes with that object.
-class ToFuture<T> extends Converter<T, Future<T>> {
-  /// Creates a new [ToFuture].
-  const ToFuture();
-
-  @override
-  Future<T> convert(T input) async => input;
-}
-
-/// Converts an object into a single-element [List] containing that object.
-class Listify<T> extends Converter<T, List<T>> {
-  /// Creates a new [Listify].
-  const Listify();
-
-  @override
-  List<T> convert(T input) => <T>[input];
-}
-
-/// Converts a simple [List<int>] to a [Uint8List].
-class ToUint8List extends Converter<List<int>, Uint8List> {
-  /// Creates a new [ToUint8List].
-  const ToUint8List();
-
-  @override
-  Uint8List convert(List<int> input) => Uint8List.fromList(input);
-}
-
-/// Revives a [Directory] entity reference into a [ReplayDirectory].
-class ReviveDirectory extends Converter<String, Directory> {
-  /// Creates a new [ReviveDirectory].
-  const ReviveDirectory(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  Directory convert(String input) => ReplayDirectory(_fileSystem, input);
-}
-
-/// Revives a [File] entity reference into a [ReplayFile].
-class ReviveFile extends Converter<String, File> {
-  /// Creates a new [ReviveFile].
-  const ReviveFile(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  File convert(String input) => ReplayFile(_fileSystem, input);
-}
-
-/// Revives a [Link] entity reference into a [ReplayLink].
-class ReviveLink extends Converter<String, Link> {
-  /// Creates a new [ReviveLink].
-  const ReviveLink(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  Link convert(String input) => ReplayLink(_fileSystem, input);
-}
-
-/// Revives a [FileSystemEntity] entity reference into a [ReplayDirectory],
-/// [ReplayFile], or a [ReplayLink] depending on the identifier of the entity
-/// reference.
-class ReviveFileSystemEntity extends Converter<String, FileSystemEntity> {
-  /// Creates a new [ReviveFileSystemEntity].
-  const ReviveFileSystemEntity(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  FileSystemEntity convert(String input) {
-    if (input.contains('Directory')) {
-      return ReplayDirectory(_fileSystem, input);
-    } else if (input.contains('File')) {
-      return ReplayFile(_fileSystem, input);
-    } else {
-      return ReplayLink(_fileSystem, input);
-    }
-  }
-}
-
-/// Revives a [RandomAccessFile] entity reference into a
-/// [ReplayRandomAccessFile].
-class ReviveRandomAccessFile extends Converter<String, RandomAccessFile> {
-  /// Creates a new [ReviveRandomAccessFile] that will derive its behavior
-  /// from the specified file system's recording.
-  const ReviveRandomAccessFile(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  RandomAccessFile convert(String input) =>
-      ReplayRandomAccessFile(_fileSystem, input);
-}
-
-/// Revives an [IOSink] entity reference into a [ReplayIOSink].
-class ReviveIOSink extends Converter<String, IOSink> {
-  /// Creates a new [ReviveIOSink] that will derive its behavior from the
-  /// specified file system's recording.
-  const ReviveIOSink(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  IOSink convert(String input) => ReplayIOSink(_fileSystem, input);
-}
-
-/// Converts all elements of a [List], returning a new [List] of converted
-/// elements.
-class ConvertElements<S, T> extends Converter<List<S>, List<T>> {
-  /// Creates a new [ConvertElements] that will use the specified
-  /// [elementConverter] to convert the elements of an [Iterable].
-  const ConvertElements(Converter<S, T> elementConverter)
-      : _delegate = elementConverter;
-
-  final Converter<S, T> _delegate;
-
-  @override
-  List<T> convert(List<S> input) => input.map(_delegate.convert).toList();
-}
-
-/// Converts a `List<S>` into a `List<T>` by casting it to the appropriate
-/// type. The list must contain only elements of type `T`, or a runtime error
-/// will be thrown.
-class CastList<S, T> extends Converter<List<S>, List<T>> {
-  /// Creates a new [CastList].
-  const CastList();
-
-  @override
-  List<T> convert(List<S> input) => input.cast<T>();
-}
-
-/// Converts a [List] of elements into a [Stream] of the same elements.
-class ToStream<T> extends Converter<List<T>, Stream<T>> {
-  /// Creates a new [ToStream].
-  const ToStream();
-
-  @override
-  Stream<T> convert(List<T> input) => Stream<T>.fromIterable(input);
-}
-
-/// Converts a blob reference (serialized as a [String] of the form
-/// `!<filename>`) into a byte list.
-class BlobToBytes extends Converter<String, Uint8List> {
-  /// Creates a new [BlobToBytes] that will use the specified file system's
-  /// recording to load the blob.
-  const BlobToBytes(this._fileSystem);
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  Uint8List convert(String input) {
-    assert(input.startsWith('!'));
-    String basename = input.substring(1);
-    String dirname = _fileSystem.recording.path;
-    String path = _fileSystem.recording.fileSystem.path.join(dirname, basename);
-    File file = _fileSystem.recording.fileSystem.file(path);
-    return file.readAsBytesSync();
-  }
-}
-
-/// Converts serialized errors into throwable objects.
-class ToError extends Converter<dynamic, dynamic> {
-  /// Creates a new [ToError].
-  const ToError();
-
-  /// Known decoders (keyed by `type`). Types not covered here will be decoded
-  /// into [InvocationException].
-  static const Map<String, Converter<Object, Object>> _decoders =
-      <String, Converter<Object, Object>>{
-    _FSExceptionCodec.type: _FSExceptionCodec.deserialize,
-    _OSErrorCodec.type: _OSErrorCodec.deserialize,
-    _ArgumentErrorCodec.type: _ArgumentErrorCodec.deserialize,
-    _NoSuchMethodErrorCodec.type: _NoSuchMethodErrorCodec.deserialize,
-  };
-
-  @override
-  dynamic convert(dynamic input) {
-    if (input is Map) {
-      String errorType = input[kManifestErrorTypeKey] as String;
-      if (_decoders.containsKey(errorType)) {
-        return _decoders[errorType].convert(input);
-      }
-    }
-    return InvocationException();
-  }
-}
-
-class _FSExceptionCodec
-    extends Codec<FileSystemException, Map<String, Object>> {
-  const _FSExceptionCodec();
-
-  static const String type = 'FileSystemException';
-
-  static Map<String, Object> _encode(FileSystemException exception) {
-    return <String, Object>{
-      kManifestErrorTypeKey: type,
-      'message': exception.message,
-      'path': exception.path,
-      'osError': encode(exception.osError),
-    };
-  }
-
-  static FileSystemException _decode(Map<String, Object> input) {
-    Object osError = input['osError'];
-    return FileSystemException(
-      input['message'] as String,
-      input['path'] as String,
-      osError == null ? null : const ToError().convert(osError) as OSError,
-    );
-  }
-
-  static const Converter<FileSystemException, Map<String, Object>> serialize =
-      _ForwardingConverter<FileSystemException, Map<String, Object>>(_encode);
-
-  static const Converter<Map<String, Object>, FileSystemException> deserialize =
-      _ForwardingConverter<Map<String, Object>, FileSystemException>(_decode);
-
-  @override
-  Converter<FileSystemException, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, FileSystemException> get decoder =>
-      deserialize;
-}
-
-class _OSErrorCodec extends Codec<OSError, Map<String, Object>> {
-  const _OSErrorCodec();
-
-  static const String type = 'OSError';
-
-  static Map<String, Object> _encode(OSError error) {
-    return <String, Object>{
-      kManifestErrorTypeKey: type,
-      'message': error.message,
-      'errorCode': error.errorCode,
-    };
-  }
-
-  static OSError _decode(Map<String, Object> input) {
-    return OSError(input['message'] as String, input['errorCode'] as int);
-  }
-
-  static const Converter<OSError, Map<String, Object>> serialize =
-      _ForwardingConverter<OSError, Map<String, Object>>(_encode);
-
-  static const Converter<Map<String, Object>, OSError> deserialize =
-      _ForwardingConverter<Map<String, Object>, OSError>(_decode);
-
-  @override
-  Converter<OSError, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, OSError> get decoder => deserialize;
-}
-
-class _ArgumentErrorCodec extends Codec<ArgumentError, Map<String, Object>> {
-  const _ArgumentErrorCodec();
-
-  static const String type = 'ArgumentError';
-
-  static Map<String, Object> _encode(ArgumentError error) {
-    return <String, Object>{
-      kManifestErrorTypeKey: type,
-      'message': encode(error.message),
-      'invalidValue': encode(error.invalidValue),
-      'name': error.name,
-    };
-  }
-
-  static ArgumentError _decode(Map<String, Object> input) {
-    dynamic message = input['message'];
-    dynamic invalidValue = input['invalidValue'];
-    String name = input['name'] as String;
-    if (invalidValue != null) {
-      return ArgumentError.value(invalidValue, name, message);
-    } else if (name != null) {
-      return ArgumentError.notNull(name);
-    } else {
-      return ArgumentError(message);
-    }
-  }
-
-  static const Converter<ArgumentError, Map<String, Object>> serialize =
-      _ForwardingConverter<ArgumentError, Map<String, Object>>(_encode);
-
-  static const Converter<Map<String, Object>, ArgumentError> deserialize =
-      _ForwardingConverter<Map<String, Object>, ArgumentError>(_decode);
-
-  @override
-  Converter<ArgumentError, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, ArgumentError> get decoder => deserialize;
-}
-
-class _NoSuchMethodErrorCodec
-    extends Codec<NoSuchMethodError, Map<String, Object>> {
-  const _NoSuchMethodErrorCodec();
-
-  static const String type = 'NoSuchMethodError';
-
-  static Map<String, Object> _encode(NoSuchMethodError error) {
-    return <String, Object>{
-      kManifestErrorTypeKey: type,
-      'toString': error.toString(),
-    };
-  }
-
-  static NoSuchMethodError _decode(Map<String, Object> input) {
-    return _NoSuchMethodError(input['toString'] as String);
-  }
-
-  static const Converter<NoSuchMethodError, Map<String, Object>> serialize =
-      _ForwardingConverter<NoSuchMethodError, Map<String, Object>>(_encode);
-
-  static const Converter<Map<String, Object>, NoSuchMethodError> deserialize =
-      _ForwardingConverter<Map<String, Object>, NoSuchMethodError>(_decode);
-
-  @override
-  Converter<NoSuchMethodError, Map<String, Object>> get encoder => serialize;
-
-  @override
-  Converter<Map<String, Object>, NoSuchMethodError> get decoder => deserialize;
-}
-
-class _NoSuchMethodError extends Error implements NoSuchMethodError {
-  _NoSuchMethodError(this._toString);
-
-  final String _toString;
-
-  @override
-  String toString() => _toString;
-}
diff --git a/packages/file/lib/src/backends/record_replay/common.dart b/packages/file/lib/src/backends/record_replay/common.dart
deleted file mode 100644
index 8fb680c..0000000
--- a/packages/file/lib/src/backends/record_replay/common.dart
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'codecs.dart';
-import 'events.dart';
-
-/// Encoded value of the file system in a recording.
-const String kFileSystemEncodedValue = '__fs__';
-
-/// The name of the recording manifest file.
-const String kManifestName = 'MANIFEST.txt';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// type of invocation.
-///
-/// See also:
-///   - [kGetType]
-///   - [kSetType]
-///   - [kInvokeType]
-const String kManifestTypeKey = 'type';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// target of the invocation.
-const String kManifestObjectKey = 'object';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// result (return value) of the invocation.
-const String kManifestResultKey = 'result';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// error that was thrown during the invocation.
-const String kManifestErrorKey = 'error';
-
-/// The key in a serialized error that is used to store the runtime type of
-/// the error that was thrown.
-const String kManifestErrorTypeKey = 'type';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// timestamp of the invocation.
-const String kManifestTimestampKey = 'timestamp';
-
-/// The key in a serialized [PropertyGetEvent] or [PropertySetEvent] map that
-/// is used to store the property that was accessed or mutated.
-const String kManifestPropertyKey = 'property';
-
-/// The key in a serialized [PropertySetEvent] map that is used to store the
-/// value to which the property was set.
-const String kManifestValueKey = 'value';
-
-/// The key in a serialized [MethodEvent] map that is used to store the name of
-/// the method that was invoked.
-const String kManifestMethodKey = 'method';
-
-/// The key in a serialized [MethodEvent] map that is used to store the
-/// positional arguments that were passed to the method.
-const String kManifestPositionalArgumentsKey = 'positionalArguments';
-
-/// The key in a serialized [MethodEvent] map that is used to store the
-/// named arguments that were passed to the method.
-const String kManifestNamedArgumentsKey = 'namedArguments';
-
-/// The key in a serialized [InvocationEvent] map that is used to store the
-/// order in which the invocation has been replayed (if it has been replayed).
-const String kManifestOrdinalKey = 'ordinal';
-
-/// The serialized [kManifestTypeKey] for property retrievals.
-const String kGetType = 'get';
-
-/// The serialized [kManifestTypeKey] for property mutations.
-const String kSetType = 'set';
-
-/// The serialized [kManifestTypeKey] for method invocations.
-const String kInvokeType = 'invoke';
-
-/// Gets an id guaranteed to be unique on this isolate for objects within this
-/// library.
-int newUid() => _nextUid++;
-int _nextUid = 1;
-
-/// Gets the name of the specified [symbol].
-// TODO(tvolkert): Symbol.name (https://github.com/dart-lang/sdk/issues/28372)
-String getSymbolName(Symbol symbol) {
-  // Format of `str` is `Symbol("<name>")`
-  String str = symbol.toString();
-  int offset = str.indexOf('"') + 1;
-  return str.substring(offset, str.indexOf('"', offset));
-}
-
-/// This class is a work-around for the "is" operator not accepting a variable
-/// value as its right operand (https://github.com/dart-lang/sdk/issues/27680).
-class TypeMatcher<T> {
-  /// Creates a type matcher for the given type parameter.
-  const TypeMatcher();
-
-  static const TypeMatcher<void> _void = TypeMatcher<void>();
-
-  /// This matcher's type, `T`.
-  Type get type => T;
-
-  /// Returns `true` if the given object is of type `T`.
-  bool matches(dynamic object) {
-    return T == _void.type ? object == T : object is T;
-  }
-}
-
-/// Marks a class that, when serialized, will be referred to merely by an
-/// opaque identifier.
-///
-/// Unlike other objects, objects that are replay-aware don't need to serialize
-/// meaningful metadata about their state for the sake of revival. Rather, they
-/// derive all the information they need to operate from the recording. As such,
-/// they are serialized using only an opaque unique identifier. When they are
-/// revived during replay, their identifier allows them to find invocations in
-/// the recording for which they are the target.
-abstract class ReplayAware {
-  /// The identifier of this object, guaranteed to be unique within a single
-  /// recording.
-  String get identifier;
-}
-
-/// Tells whether two objects are equal using deep equality checking.
-///
-/// Two lists are deeply equal if they have the same runtime type, the same
-/// length, and every element in list A is pairwise deeply equal with the
-/// corresponding element in list B.
-///
-/// Two maps are deeply equal if they have the same runtime type, the same
-/// length, the same set of keys, and the value for every key in map A is
-/// deeply equal to the corresponding value in map B.
-///
-/// All other types of objects are deeply equal if they have the same runtime
-/// type and are logically equal (according to `operator==`).
-bool deeplyEqual(dynamic object1, dynamic object2) {
-  if (object1.runtimeType != object2.runtimeType) {
-    return false;
-  } else if (object1 is List) {
-    return _areListsEqual<dynamic>(object1, object2 as List<dynamic>);
-  } else if (object1 is Map) {
-    return _areMapsEqual<dynamic, dynamic>(
-        object1, object2 as Map<dynamic, dynamic>);
-  } else {
-    return object1 == object2;
-  }
-}
-
-bool _areListsEqual<T>(List<T> list1, List<T> list2) {
-  int i = 0;
-  return list1.length == list2.length &&
-      list1.every((T element) => deeplyEqual(element, list2[i++]));
-}
-
-bool _areMapsEqual<K, V>(Map<K, V> map1, Map<K, V> map2) {
-  return map1.length == map2.length &&
-      map1.keys.every((K key) {
-        return map1.containsKey(key) == map2.containsKey(key) &&
-            deeplyEqual(map1[key], map2[key]);
-      });
-}
-
-/// Returns a human-readable representation of an [Invocation].
-String describeInvocation(Invocation invocation) {
-  final StringBuffer buffer = StringBuffer()
-    ..write(getSymbolName(invocation.memberName));
-  if (invocation.isMethod) {
-    buffer.write('(');
-    int printedCount = 0;
-    for (dynamic arg in invocation.positionalArguments) {
-      if (printedCount > 0) {
-        buffer.write(', ');
-      }
-      buffer.write(Error.safeToString(encode(arg)));
-      printedCount += 1;
-    }
-    for (final MapEntry<Symbol, dynamic> nameValue
-        in invocation.namedArguments.entries) {
-      final Symbol name = nameValue.key;
-      final dynamic value = nameValue.value;
-      if (printedCount > 0) {
-        buffer.write(', ');
-      }
-      buffer.write(
-          '${getSymbolName(name)}: ${Error.safeToString(encode(value))}');
-      printedCount += 1;
-    }
-    buffer.write(')');
-  } else if (invocation.isSetter) {
-    buffer
-      ..write(' = ')
-      ..write(Error.safeToString(encode(invocation.positionalArguments[0])));
-  }
-  return buffer.toString();
-}
diff --git a/packages/file/lib/src/backends/record_replay/errors.dart b/packages/file/lib/src/backends/record_replay/errors.dart
deleted file mode 100644
index 3d3fa12..0000000
--- a/packages/file/lib/src/backends/record_replay/errors.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'common.dart';
-
-/// Error thrown during replay when there is no matching invocation in the
-/// recording.
-class NoMatchingInvocationError extends Error {
-  /// Creates a new `NoMatchingInvocationError` caused by the failure to replay
-  /// the specified [invocation].
-  NoMatchingInvocationError(this.invocation);
-
-  /// The invocation that was unable to be replayed.
-  final Invocation invocation;
-
-  @override
-  String toString() =>
-      'No matching invocation found: ${describeInvocation(invocation)}';
-}
-
-/// Exception thrown during replay when an invocation recorded error, but we
-/// were unable to find a type-specific converter to deserialize the recorded
-/// error into a more specific exception type.
-class InvocationException implements Exception {}
diff --git a/packages/file/lib/src/backends/record_replay/events.dart b/packages/file/lib/src/backends/record_replay/events.dart
deleted file mode 100644
index 01e5ff4..0000000
--- a/packages/file/lib/src/backends/record_replay/events.dart
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'codecs.dart';
-import 'common.dart';
-import 'recording.dart';
-import 'result_reference.dart';
-
-/// Base class for recordable file system invocation events.
-///
-/// Instances of this class will be aggregated in a [Recording]
-abstract class InvocationEvent<T> {
-  /// The object on which the invocation occurred. Will always be non-null.
-  Object get object;
-
-  /// The return value of the invocation if the invocation completed
-  /// successfully.
-  ///
-  /// This may be null (and will always be `null` for setters).
-  ///
-  /// If the invocation completed with an error, this value will be `null`,
-  /// and [error] will be set.
-  T get result;
-
-  /// The error that was thrown by the invocation if the invocation completed
-  /// with an error.
-  ///
-  /// If the invocation completed successfully, this value will be `null`, and
-  /// [result] will hold the result of the invocation (which may also be
-  /// `null`).
-  ///
-  /// This field being non-null can be used as an indication that the invocation
-  /// completed with an error.
-  dynamic get error;
-
-  /// The stopwatch value (in milliseconds) when the invocation occurred.
-  ///
-  /// This value is recorded when the invocation first occurs, not when the
-  /// delegate returns.
-  int get timestamp;
-}
-
-/// A recordable invocation of a property getter on a file system object.
-abstract class PropertyGetEvent<T> extends InvocationEvent<T> {
-  /// The property that was retrieved.
-  Symbol get property;
-}
-
-/// A recordable invocation of a property setter on a file system object.
-abstract class PropertySetEvent<T> extends InvocationEvent<Null> {
-  /// The property that was set.
-  ///
-  /// All setter property symbols will have a trailing equals sign. For example,
-  /// if the `foo` property was set, this value will be a symbol of `foo=`.
-  Symbol get property;
-
-  /// The value to which [property] was set. This is distinct from [result],
-  /// which is always `null` for setters.
-  T get value;
-}
-
-/// A recordable invocation of a method on a file system object.
-abstract class MethodEvent<T> extends InvocationEvent<T> {
-  /// The method that was invoked.
-  Symbol get method;
-
-  /// The positional arguments that were passed to the method.
-  List<dynamic> get positionalArguments;
-
-  /// The named arguments that were passed to the method.
-  Map<Symbol, dynamic> get namedArguments;
-}
-
-/// An [InvocationEvent] that's in the process of being recorded.
-abstract class LiveInvocationEvent<T> implements InvocationEvent<T> {
-  /// Creates a new [LiveInvocationEvent].
-  LiveInvocationEvent(this.object, this._result, this.error, this.timestamp);
-
-  final dynamic _result;
-
-  @override
-  final Object object;
-
-  @override
-  T get result {
-    dynamic result = _result;
-    while (result is ResultReference) {
-      ResultReference<dynamic> reference = result as ResultReference<dynamic>;
-      result = reference.recordedValue;
-    }
-    return result as T;
-  }
-
-  @override
-  final dynamic error;
-
-  @override
-  final int timestamp;
-
-  /// A [Future] that completes once [result] is ready for serialization.
-  ///
-  /// If [result] is a [Future], this future completes when [result] completes.
-  /// If [result] is a [Stream], this future completes when the stream sends a
-  /// "done" event. If [result] is neither a future nor a stream, this future
-  /// completes immediately.
-  ///
-  /// It is legal for [serialize] to be called before this future completes,
-  /// but doing so will cause incomplete results to be serialized. Results that
-  /// are unfinished futures will be serialized as `null`, and results that are
-  /// unfinished streams will be serialized as the data that has been received
-  /// thus far.
-  Future<void> get done async {
-    dynamic result = _result;
-    while (result is ResultReference) {
-      ResultReference<dynamic> reference = result as ResultReference<dynamic>;
-      await reference.complete;
-      result = reference.recordedValue;
-    }
-  }
-
-  /// Returns this event as a JSON-serializable object.
-  Map<String, dynamic> serialize() {
-    return <String, dynamic>{
-      kManifestObjectKey: encode(object),
-      kManifestResultKey: encode(_result),
-      kManifestErrorKey: encode(error),
-      kManifestTimestampKey: timestamp,
-    };
-  }
-
-  @override
-  String toString() => serialize().toString();
-}
-
-/// A [PropertyGetEvent] that's in the process of being recorded.
-class LivePropertyGetEvent<T> extends LiveInvocationEvent<T>
-    implements PropertyGetEvent<T> {
-  /// Creates a new [LivePropertyGetEvent].
-  LivePropertyGetEvent(
-      Object object, this.property, T result, dynamic error, int timestamp)
-      : super(object, result, error, timestamp);
-
-  @override
-  final Symbol property;
-
-  @override
-  Map<String, dynamic> serialize() {
-    return <String, dynamic>{
-      kManifestTypeKey: kGetType,
-      kManifestPropertyKey: getSymbolName(property),
-    }..addAll(super.serialize());
-  }
-}
-
-/// A [PropertySetEvent] that's in the process of being recorded.
-class LivePropertySetEvent<T> extends LiveInvocationEvent<Null>
-    implements PropertySetEvent<T> {
-  /// Creates a new [LivePropertySetEvent].
-  LivePropertySetEvent(
-      Object object, this.property, this.value, dynamic error, int timestamp)
-      : super(object, null, error, timestamp);
-
-  @override
-  final Symbol property;
-
-  @override
-  final T value;
-
-  @override
-  Map<String, dynamic> serialize() {
-    return <String, dynamic>{
-      kManifestTypeKey: kSetType,
-      kManifestPropertyKey: getSymbolName(property),
-      kManifestValueKey: encode(value),
-    }..addAll(super.serialize());
-  }
-}
-
-/// A [MethodEvent] that's in the process of being recorded.
-class LiveMethodEvent<T> extends LiveInvocationEvent<T>
-    implements MethodEvent<T> {
-  /// Creates a new [LiveMethodEvent].
-  LiveMethodEvent(
-    Object object,
-    this.method,
-    List<dynamic> positionalArguments,
-    Map<Symbol, dynamic> namedArguments,
-    T result,
-    dynamic error,
-    int timestamp,
-  )   : positionalArguments = List<dynamic>.unmodifiable(positionalArguments),
-        namedArguments = Map<Symbol, dynamic>.unmodifiable(namedArguments),
-        super(object, result, error, timestamp);
-
-  @override
-  final Symbol method;
-
-  @override
-  final List<dynamic> positionalArguments;
-
-  @override
-  final Map<Symbol, dynamic> namedArguments;
-
-  @override
-  Map<String, dynamic> serialize() {
-    return <String, dynamic>{
-      kManifestTypeKey: kInvokeType,
-      kManifestMethodKey: getSymbolName(method),
-      kManifestPositionalArgumentsKey: encode(positionalArguments),
-      kManifestNamedArgumentsKey: encode(namedArguments),
-    }..addAll(super.serialize());
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/mutable_recording.dart b/packages/file/lib/src/backends/record_replay/mutable_recording.dart
deleted file mode 100644
index ec30905..0000000
--- a/packages/file/lib/src/backends/record_replay/mutable_recording.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'common.dart';
-import 'events.dart';
-import 'recording.dart';
-
-/// A mutable live recording.
-class MutableRecording implements LiveRecording {
-  /// Creates a new `MutableRecording` that will serialize its data to the
-  /// specified [destination].
-  MutableRecording(this.destination);
-
-  final List<LiveInvocationEvent<dynamic>> _events =
-      <LiveInvocationEvent<dynamic>>[];
-
-  bool _flushing = false;
-
-  @override
-  final Directory destination;
-
-  @override
-  List<LiveInvocationEvent<dynamic>> get events =>
-      List<LiveInvocationEvent<dynamic>>.unmodifiable(_events);
-
-  @override
-  Future<void> flush({Duration pendingResultTimeout}) async {
-    if (_flushing) {
-      throw StateError('Recording is already flushing');
-    }
-    _flushing = true;
-    try {
-      Iterable<Future<void>> futures =
-          _events.map((LiveInvocationEvent<dynamic> event) => event.done);
-      Future<List<void>> results = Future.wait<void>(futures);
-      if (pendingResultTimeout != null) {
-        results = results.timeout(pendingResultTimeout, onTimeout: () {
-          return null;
-        });
-      }
-      await results;
-      Directory dir = destination;
-      String json = const JsonEncoder.withIndent('  ').convert(encode(_events));
-      String filename = dir.fileSystem.path.join(dir.path, kManifestName);
-      await dir.fileSystem.file(filename).writeAsString(json, flush: true);
-    } finally {
-      _flushing = false;
-    }
-  }
-
-  /// Returns a new file for use with this recording.
-  ///
-  /// The file name will combine the specified [name] with [newUid] to ensure
-  /// that its name is unique among all recording files.
-  ///
-  /// It is up to the caller to create the file - it will not exist in the
-  /// file system when it is returned from this method.
-  File newFile(String name) {
-    String basename = '${newUid()}.$name';
-    String dirname = destination.path;
-    String path = destination.fileSystem.path.join(dirname, basename);
-    return destination.fileSystem.file(path);
-  }
-
-  /// Adds the specified [event] to this recording.
-  void add(LiveInvocationEvent<dynamic> event) => _events.add(event);
-}
diff --git a/packages/file/lib/src/backends/record_replay/proxy.dart b/packages/file/lib/src/backends/record_replay/proxy.dart
deleted file mode 100644
index 06cf974..0000000
--- a/packages/file/lib/src/backends/record_replay/proxy.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// An object that uses [noSuchMethod] to dynamically handle invocations
-/// (property getters, property setters, and method invocations).
-abstract class ProxyObject {}
-
-/// A function reference that, when invoked, will forward the invocation back
-/// to a [ProxyObject].
-///
-/// This is used when a caller accesses a method on a [ProxyObject] via the
-/// method's getter. In these cases, the caller will receive a [MethodProxy]
-/// that allows delayed invocation of the method.
-class MethodProxy {
-  /// Creates a new [MethodProxy] that, when invoked, will invoke the method
-  /// identified by [methodName] on the specified target [object].
-  MethodProxy(ProxyObject object, Symbol methodName)
-      : _proxyObject = object,
-        _methodName = methodName;
-
-  /// The object on which the method was retrieved.
-  ///
-  /// This will be the target object when this method proxy is invoked.
-  final ProxyObject _proxyObject;
-
-  /// The name of the method in question.
-  final Symbol _methodName;
-
-  @override
-  dynamic noSuchMethod(Invocation invocation) {
-    if (invocation.isMethod && invocation.memberName == #call) {
-      // The method is being invoked. Capture the arguments, and invoke the
-      // method on the proxy object. We have to synthesize an invocation, since
-      // our current `invocation` object represents the invocation of `call()`.
-      return _proxyObject.noSuchMethod(Invocation.method(
-        _methodName,
-        invocation.positionalArguments,
-        invocation.namedArguments,
-      ));
-    }
-    return super.noSuchMethod(invocation);
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording.dart b/packages/file/lib/src/backends/record_replay/recording.dart
deleted file mode 100644
index d5f7901..0000000
--- a/packages/file/lib/src/backends/record_replay/recording.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:file/file.dart';
-
-import 'events.dart';
-import 'replay_file_system.dart';
-
-/// A recording of a series of invocations on a [FileSystem] and its associated
-/// objects (`File`, `Directory`, `IOSink`, etc).
-///
-/// Recorded invocations include property getters, property setters, and
-/// standard method invocations. A recording exists as an ordered series of
-/// "invocation events".
-abstract class Recording {
-  /// The invocation events that have been captured by this recording.
-  List<InvocationEvent<dynamic>> get events;
-}
-
-/// An [Recording] in progress that can be serialized to disk for later use
-/// in [ReplayFileSystem].
-///
-/// Live recordings exist only in memory until [flush] is called.
-abstract class LiveRecording extends Recording {
-  /// The directory in which recording files will be stored.
-  ///
-  /// These contents of these files, while human readable, do not constitute an
-  /// API or contract. Their makeup and structure is subject to change from
-  /// one version of `package:file` to the next.
-  Directory get destination;
-
-  /// Writes this recording to disk.
-  ///
-  /// Live recordings will *not* call `flush` on themselves, so it is up to
-  /// callers to call this method when they wish to write the recording to
-  /// disk.
-  ///
-  /// If [pendingResultTimeout] is specified, this will wait the specified
-  /// duration for any results that are `Future`s or `Stream`s to complete
-  /// before serializing the recording to disk. Futures that don't complete
-  /// within the specified duration will have their results recorded as `null`,
-  /// and streams that don't send a "done" event within the specified duration
-  /// will have their results recorded as the list of events the stream has
-  /// fired thus far.
-  ///
-  /// If [pendingResultTimeout] is not specified (or is `null`), this will wait
-  /// indefinitely for for any results that are `Future`s or `Stream`s to
-  /// complete before serializing the recording to disk.
-  ///
-  /// Throws a [StateError] if a flush is already in progress.
-  ///
-  /// Returns a future that completes once the recording has been fully written
-  /// to disk.
-  Future<void> flush({Duration pendingResultTimeout});
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_directory.dart b/packages/file/lib/src/backends/record_replay/recording_directory.dart
deleted file mode 100644
index e157327..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_directory.dart
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:file/file.dart';
-import 'package:file/src/io.dart' as io;
-
-import 'recording_file_system.dart';
-import 'recording_file_system_entity.dart';
-
-/// [Directory] implementation that records all invocation activity to its file
-/// system's recording.
-class RecordingDirectory extends RecordingFileSystemEntity<Directory>
-    implements Directory {
-  /// Creates a new `RecordingDirectory`.
-  RecordingDirectory(RecordingFileSystem fileSystem, io.Directory delegate)
-      : super(fileSystem as RecordingFileSystemImpl, delegate as Directory) {
-    methods.addAll(<Symbol, Function>{
-      #create: _create,
-      #createSync: delegate.createSync,
-      #createTemp: _createTemp,
-      #createTempSync: _createTempSync,
-      #list: _list,
-      #listSync: _listSync,
-      #childDirectory: _childDirectory,
-      #childFile: _childFile,
-      #childLink: _childLink,
-    });
-  }
-
-  // These four abstract methods, [create], [createSync], [list], and [listSync],
-  // are implemented by [noSuchMethod], but their presence here works around
-  // https://github.com/dart-lang/sdk/issues/33459, allowing these methods to
-  // be called within a Dart 2 runtime.
-  // TODO(srawlins): Remove these when the minimum SDK version in
-  // `pubspec.yaml` contains a fix for
-  // https://github.com/dart-lang/sdk/issues/33459.
-
-  @override
-  Future<Directory> create({bool recursive = false});
-
-  @override
-  void createSync({bool recursive = false});
-
-  @override
-  Stream<FileSystemEntity> list(
-      {bool recursive = false, bool followLinks = true});
-
-  @override
-  List<FileSystemEntity> listSync(
-      {bool recursive = false, bool followLinks = true});
-
-  @override
-  Directory wrap(Directory delegate) =>
-      super.wrap(delegate) ?? wrapDirectory(delegate);
-
-  Future<Directory> _create({bool recursive = false}) =>
-      delegate.create(recursive: recursive).then(wrap);
-
-  Future<Directory> _createTemp([String prefix]) =>
-      delegate.createTemp(prefix).then(wrap);
-
-  Directory _createTempSync([String prefix]) =>
-      wrap(delegate.createTempSync(prefix));
-
-  Stream<FileSystemEntity> _list(
-          {bool recursive = false, bool followLinks = true}) =>
-      delegate
-          .list(recursive: recursive, followLinks: followLinks)
-          .map(_wrapGeneric);
-
-  List<FileSystemEntity> _listSync(
-          {bool recursive = false, bool followLinks = true}) =>
-      delegate
-          .listSync(recursive: recursive, followLinks: followLinks)
-          .map(_wrapGeneric)
-          .toList();
-
-  FileSystemEntity _wrapGeneric(io.FileSystemEntity entity) {
-    if (entity is io.File) {
-      return wrapFile(entity);
-    } else if (entity is io.Directory) {
-      return wrapDirectory(entity);
-    } else if (entity is io.Link) {
-      return wrapLink(entity);
-    }
-    throw FileSystemException('Unsupported type: $entity', entity.path);
-  }
-
-  Directory _childDirectory(String basename) =>
-      wrapDirectory(delegate.childDirectory(basename));
-
-  File _childFile(String basename) => wrapFile(delegate.childFile(basename));
-
-  Link _childLink(String basename) => wrapLink(delegate.childLink(basename));
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_file.dart b/packages/file/lib/src/backends/record_replay/recording_file.dart
deleted file mode 100644
index cc9b03e..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_file.dart
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:meta/meta.dart';
-import 'package:file/file.dart';
-import 'package:file/src/io.dart' as io;
-
-import 'recording_file_system.dart';
-import 'recording_file_system_entity.dart';
-import 'recording_io_sink.dart';
-import 'recording_random_access_file.dart';
-import 'result_reference.dart';
-
-/// Callback responsible for synchronously writing result [data] to the
-/// specified [file].
-///
-/// See also:
-///   - [_BlobReference]
-///   - [_BlobStreamReference]
-typedef _BlobDataSyncWriter<T> = void Function(File file, T data);
-
-/// Callback responsible for asynchronously writing result [data] to the
-/// specified [file].
-///
-/// See also:
-///   - [_BlobFutureReference]
-typedef _BlobDataAsyncWriter<T> = Future<void> Function(File file, T data);
-
-/// [File] implementation that records all invocation activity to its file
-/// system's recording.
-class RecordingFile extends RecordingFileSystemEntity<File> implements File {
-  /// Creates a new `RecordingFile`.
-  RecordingFile(RecordingFileSystem fileSystem, io.File delegate)
-      : super(fileSystem as RecordingFileSystemImpl, delegate as File) {
-    methods.addAll(<Symbol, Function>{
-      #create: _create,
-      #createSync: delegate.createSync,
-      #copy: _copy,
-      #copySync: _copySync,
-      #length: delegate.length,
-      #lengthSync: delegate.lengthSync,
-      #lastAccessed: delegate.lastAccessed,
-      #lastAccessedSync: delegate.lastAccessedSync,
-      #setLastAccessed: delegate.setLastAccessed,
-      #setLastAccessedSync: delegate.setLastAccessedSync,
-      #lastModified: delegate.lastModified,
-      #lastModifiedSync: delegate.lastModifiedSync,
-      #setLastModified: delegate.setLastModified,
-      #setLastModifiedSync: delegate.setLastModifiedSync,
-      #open: _open,
-      #openSync: _openSync,
-      #openRead: _openRead,
-      #openWrite: _openWrite,
-      #readAsBytes: _readAsBytes,
-      #readAsBytesSync: _readAsBytesSync,
-      #readAsString: _readAsString,
-      #readAsStringSync: _readAsStringSync,
-      #readAsLines: _readAsLines,
-      #readAsLinesSync: _readAsLinesSync,
-      #writeAsBytes: _writeAsBytes,
-      #writeAsBytesSync: delegate.writeAsBytesSync,
-      #writeAsString: _writeAsString,
-      #writeAsStringSync: delegate.writeAsStringSync,
-    });
-  }
-
-  @override
-  File wrap(File delegate) => super.wrap(delegate) ?? wrapFile(delegate);
-
-  File _newRecordingFile() => recording.newFile(delegate.basename);
-
-  RandomAccessFile _wrapRandomAccessFile(RandomAccessFile delegate) =>
-      RecordingRandomAccessFile(fileSystem, delegate);
-
-  Future<File> _create({bool recursive = false}) =>
-      delegate.create(recursive: recursive).then(wrap);
-
-  Future<File> _copy(String newPath) => delegate.copy(newPath).then(wrap);
-
-  File _copySync(String newPath) => wrap(delegate.copySync(newPath));
-
-  Future<RandomAccessFile> _open({FileMode mode = FileMode.read}) =>
-      delegate.open(mode: mode).then(_wrapRandomAccessFile);
-
-  RandomAccessFile _openSync({FileMode mode = FileMode.read}) =>
-      _wrapRandomAccessFile(delegate.openSync(mode: mode));
-
-  StreamReference<Uint8List> _openRead([int start, int end]) {
-    return _BlobStreamReference<Uint8List>(
-      file: _newRecordingFile(),
-      stream: delegate.openRead(start, end).cast<Uint8List>(),
-      writer: (File file, Uint8List bytes) {
-        file.writeAsBytesSync(bytes, mode: FileMode.append, flush: true);
-      },
-    );
-  }
-
-  IOSink _openWrite(
-      {FileMode mode = FileMode.write, Encoding encoding = utf8}) {
-    return RecordingIOSink(
-      fileSystem,
-      delegate.openWrite(mode: mode, encoding: encoding),
-    );
-  }
-
-  FutureReference<Uint8List> _readAsBytes() {
-    return _BlobFutureReference<Uint8List>(
-      file: _newRecordingFile(),
-      future: delegate.readAsBytes(),
-      writer: (File file, Uint8List bytes) async {
-        await file.writeAsBytes(bytes, flush: true);
-      },
-    );
-  }
-
-  ResultReference<Uint8List> _readAsBytesSync() {
-    return _BlobReference<Uint8List>(
-      file: _newRecordingFile(),
-      value: delegate.readAsBytesSync(),
-      writer: (File file, Uint8List bytes) {
-        file.writeAsBytesSync(bytes, flush: true);
-      },
-    );
-  }
-
-  FutureReference<String> _readAsString({Encoding encoding = utf8}) {
-    return _BlobFutureReference<String>(
-      file: _newRecordingFile(),
-      future: delegate.readAsString(encoding: encoding),
-      writer: (File file, String content) async {
-        await file.writeAsString(content, flush: true);
-      },
-    );
-  }
-
-  ResultReference<String> _readAsStringSync({Encoding encoding = utf8}) {
-    return _BlobReference<String>(
-      file: _newRecordingFile(),
-      value: delegate.readAsStringSync(encoding: encoding),
-      writer: (File file, String content) {
-        file.writeAsStringSync(content, flush: true);
-      },
-    );
-  }
-
-  FutureReference<List<String>> _readAsLines({Encoding encoding = utf8}) {
-    return _BlobFutureReference<List<String>>(
-      file: _newRecordingFile(),
-      future: delegate.readAsLines(encoding: encoding),
-      writer: (File file, List<String> lines) async {
-        await file.writeAsString(_joinLines(lines), flush: true);
-      },
-    );
-  }
-
-  ResultReference<List<String>> _readAsLinesSync({Encoding encoding = utf8}) {
-    return _BlobReference<List<String>>(
-      file: _newRecordingFile(),
-      value: delegate.readAsLinesSync(encoding: encoding),
-      writer: (File file, List<String> lines) {
-        file.writeAsStringSync(_joinLines(lines), flush: true);
-      },
-    );
-  }
-
-  Future<File> _writeAsBytes(
-    List<int> bytes, {
-    FileMode mode = FileMode.write,
-    bool flush = false,
-  }) =>
-      delegate.writeAsBytes(bytes, mode: mode, flush: flush).then(wrap);
-
-  Future<File> _writeAsString(
-    String contents, {
-    FileMode mode = FileMode.write,
-    Encoding encoding = utf8,
-    bool flush = false,
-  }) =>
-      delegate
-          .writeAsString(contents, mode: mode, encoding: encoding, flush: flush)
-          .then(wrap);
-}
-
-/// A [ResultReference] that serializes its value data to a separate file.
-class _BlobReference<T> extends ResultReference<T> {
-  _BlobReference({
-    @required File file,
-    @required T value,
-    @required _BlobDataSyncWriter<T> writer,
-  })  : _file = file,
-        _value = value,
-        _writer = writer;
-
-  final File _file;
-  final T _value;
-  final _BlobDataSyncWriter<T> _writer;
-
-  @override
-  T get value {
-    _writer(_file, _value);
-    return _value;
-  }
-
-  @override
-  T get recordedValue => _value;
-
-  @override
-  String get serializedValue => '!${_file.basename}';
-}
-
-/// A [FutureReference] that serializes its value data to a separate file.
-class _BlobFutureReference<T> extends FutureReference<T> {
-  _BlobFutureReference({
-    @required File file,
-    @required Future<T> future,
-    @required _BlobDataAsyncWriter<T> writer,
-  })  : _file = file,
-        _writer = writer,
-        super(future);
-
-  final File _file;
-  final _BlobDataAsyncWriter<T> _writer;
-
-  @override
-  Future<T> get value {
-    return super.value.then((T value) async {
-      await _writer(_file, value);
-      return value;
-    });
-  }
-
-  @override
-  String get serializedValue => '!${_file.basename}';
-}
-
-/// A [StreamReference] that serializes its value data to a separate file.
-class _BlobStreamReference<T> extends StreamReference<T> {
-  _BlobStreamReference({
-    @required File file,
-    @required Stream<T> stream,
-    @required _BlobDataSyncWriter<T> writer,
-  })  : _file = file,
-        _writer = writer,
-        super(stream);
-
-  final File _file;
-  final _BlobDataSyncWriter<T> _writer;
-
-  @override
-  void onData(T event) {
-    _writer(_file, event);
-  }
-
-  @override
-  String get serializedValue => '!${_file.basename}';
-}
-
-/// Flattens a list of lines into a single, newline-delimited string.
-///
-/// Each element of [lines] is assumed to represent a complete line and will
-/// be end with a newline in the resulting string.
-String _joinLines(List<String> lines) =>
-    lines.isEmpty ? '' : (lines.join('\n') + '\n');
diff --git a/packages/file/lib/src/backends/record_replay/recording_file_system.dart b/packages/file/lib/src/backends/record_replay/recording_file_system.dart
deleted file mode 100644
index dd6a768..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_file_system.dart
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:file/file.dart';
-import 'package:meta/meta.dart';
-
-import 'common.dart';
-import 'mutable_recording.dart';
-import 'recording.dart';
-import 'recording_directory.dart';
-import 'recording_file.dart';
-import 'recording_link.dart';
-import 'recording_proxy_mixin.dart';
-import 'replay_file_system.dart';
-
-/// File system that records invocations for later playback in tests.
-///
-/// This will record all invocations (methods, property getters, and property
-/// setters) that occur on it, in an opaque format that can later be used in
-/// [ReplayFileSystem]. All activity in the [File], [Directory], [Link],
-/// [IOSink], and [RandomAccessFile] instances returned from this API will also
-/// be recorded.
-///
-/// This class is intended for use in tests, where you would otherwise have to
-/// set up complex mocks or fake file systems. With this class, the process is
-/// as follows:
-///
-///   - You record the file system activity during a real run of your program
-///     by injecting a `RecordingFileSystem` that delegates to your real file
-///     system.
-///   - You serialize that recording to disk as your program finishes.
-///   - You use that recording in tests to create a mock file system that knows
-///     how to respond to the exact invocations your program makes. Any
-///     invocations that aren't in the recording will throw, and you can make
-///     assertions in your tests about which methods were invoked and in what
-///     order.
-///
-/// *Implementation note*: this class uses [noSuchMethod] to dynamically handle
-/// invocations. As a result, method references on objects herein will not pass
-/// `is` checks or checked-mode checks on type. For example:
-///
-/// ```dart
-/// typedef FileStat StatSync(String path);
-/// FileSystem fs = RecordingFileSystem(delegate: delegate, destination: dir);
-///
-/// StatSync method = fs.statSync;     // Will fail in checked-mode
-/// fs.statSync is StatSync            // Will return false
-/// fs.statSync is Function            // Will return false
-///
-/// dynamic method2 = fs.statSync;     // OK
-/// FileStat stat = method2('/path');  // OK
-/// ```
-///
-/// See also:
-///   - [ReplayFileSystem]
-abstract class RecordingFileSystem extends FileSystem {
-  /// Creates a new `RecordingFileSystem`.
-  ///
-  /// Invocations will be recorded and forwarded to the specified [delegate]
-  /// file system.
-  ///
-  /// The recording will be serialized to the specified [destination] directory
-  /// (only when `flush` is called on this file system's [recording]).
-  ///
-  /// If [stopwatch] is specified, it will be assumed to have already been
-  /// started by the caller, and it will be used to record timestamps on each
-  /// recorded invocation. If `stopwatch` is unspecified (or `null`), a new
-  /// stopwatch will be created and started immediately to record these
-  /// timestamps.
-  factory RecordingFileSystem({
-    @required FileSystem delegate,
-    @required Directory destination,
-    Stopwatch stopwatch,
-  }) =>
-      RecordingFileSystemImpl(delegate, destination, stopwatch);
-
-  /// The file system to which invocations will be forwarded upon recording.
-  FileSystem get delegate;
-
-  /// The recording generated by invocations on this file system.
-  ///
-  /// The recording provides access to the invocation events that have been
-  /// recorded thus far, as well as the ability to flush them to disk.
-  LiveRecording get recording;
-
-  /// The stopwatch used to record timestamps on invocation events.
-  ///
-  /// Timestamps will be recorded before the delegate is invoked (not after
-  /// the delegate returns).
-  Stopwatch get stopwatch;
-}
-
-/// Non-exported implementation class for `RecordingFileSystem`.
-class RecordingFileSystemImpl extends FileSystem
-    with RecordingProxyMixin
-    implements RecordingFileSystem {
-  /// Creates a new `RecordingFileSystemImpl`.
-  RecordingFileSystemImpl(
-      this.delegate, Directory destination, Stopwatch recordingStopwatch)
-      : recording = MutableRecording(destination),
-        stopwatch = recordingStopwatch ?? Stopwatch() {
-    if (recordingStopwatch == null) {
-      // We instantiated our own stopwatch, so start it ourselves.
-      stopwatch.start();
-    }
-
-    methods.addAll(<Symbol, Function>{
-      #directory: _directory,
-      #file: _file,
-      #link: _link,
-      #stat: delegate.stat,
-      #statSync: delegate.statSync,
-      #identical: delegate.identical,
-      #identicalSync: delegate.identicalSync,
-      #type: delegate.type,
-      #typeSync: delegate.typeSync,
-    });
-
-    properties.addAll(<Symbol, Function>{
-      #path: () => delegate.path,
-      #systemTempDirectory: _getSystemTempDirectory,
-      #currentDirectory: _getCurrentDirectory,
-      const Symbol('currentDirectory='): _setCurrentDirectory,
-      #isWatchSupported: () => delegate.isWatchSupported,
-    });
-  }
-
-  @override
-  String get identifier => kFileSystemEncodedValue;
-
-  /// The file system to which invocations will be forwarded upon recording.
-  @override
-  final FileSystem delegate;
-
-  /// The recording generated by invocations on this file system.
-  @override
-  final MutableRecording recording;
-
-  /// The stopwatch used to record timestamps on invocation events.
-  @override
-  final Stopwatch stopwatch;
-
-  Directory _directory(dynamic path) =>
-      RecordingDirectory(this, delegate.directory(path));
-
-  File _file(dynamic path) => RecordingFile(this, delegate.file(path));
-
-  Link _link(dynamic path) => RecordingLink(this, delegate.link(path));
-
-  Directory _getSystemTempDirectory() =>
-      RecordingDirectory(this, delegate.systemTempDirectory);
-
-  Directory _getCurrentDirectory() =>
-      RecordingDirectory(this, delegate.currentDirectory);
-
-  void _setCurrentDirectory(dynamic value) {
-    delegate.currentDirectory = value;
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_file_system_entity.dart b/packages/file/lib/src/backends/record_replay/recording_file_system_entity.dart
deleted file mode 100644
index 236994e..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_file_system_entity.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:file/file.dart';
-import 'package:file/src/io.dart' as io;
-import 'package:meta/meta.dart';
-
-import 'common.dart';
-import 'mutable_recording.dart';
-import 'recording_directory.dart';
-import 'recording_file.dart';
-import 'recording_file_system.dart';
-import 'recording_link.dart';
-import 'recording_proxy_mixin.dart';
-
-/// [FileSystemEntity] implementation that records all invocation activity to
-/// its file system's recording.
-abstract class RecordingFileSystemEntity<T extends FileSystemEntity>
-    extends Object with RecordingProxyMixin implements FileSystemEntity {
-  /// Creates a new `RecordingFileSystemEntity`.
-  RecordingFileSystemEntity(this.fileSystem, this.delegate) {
-    methods.addAll(<Symbol, Function>{
-      #exists: delegate.exists,
-      #existsSync: delegate.existsSync,
-      #rename: _rename,
-      #renameSync: _renameSync,
-      #resolveSymbolicLinks: delegate.resolveSymbolicLinks,
-      #resolveSymbolicLinksSync: delegate.resolveSymbolicLinksSync,
-      #stat: delegate.stat,
-      #statSync: delegate.statSync,
-      #delete: _delete,
-      #deleteSync: delegate.deleteSync,
-      #watch: delegate.watch,
-    });
-
-    properties.addAll(<Symbol, Function>{
-      #path: () => delegate.path,
-      #uri: () => delegate.uri,
-      #isAbsolute: () => delegate.isAbsolute,
-      #absolute: _getAbsolute,
-      #parent: _getParent,
-      #basename: () => delegate.basename,
-      #dirname: () => delegate.dirname,
-    });
-  }
-
-  /// A unique entity id.
-  final int uid = newUid();
-
-  @override
-  String get identifier => '$runtimeType@$uid';
-
-  @override
-  final RecordingFileSystemImpl fileSystem;
-
-  @override
-  MutableRecording get recording => fileSystem.recording;
-
-  @override
-  Stopwatch get stopwatch => fileSystem.stopwatch;
-
-  /// The entity to which this entity delegates its functionality while
-  /// recording.
-  @protected
-  final T delegate;
-
-  /// Returns an entity with the same file system and same type as this
-  /// entity but backed by the specified delegate.
-  ///
-  /// This base implementation checks to see if the specified delegate is the
-  /// same as this entity's delegate, and if so, it returns this entity.
-  /// Otherwise it returns `null`. Subclasses should override this method to
-  /// instantiate the correct wrapped type only if this super implementation
-  /// returns `null`.
-  @protected
-  @mustCallSuper
-  T wrap(T delegate) => delegate == this.delegate ? this as T : null;
-
-  /// Returns a directory with the same file system as this entity but backed
-  /// by the specified delegate directory.
-  @protected
-  Directory wrapDirectory(io.Directory delegate) =>
-      RecordingDirectory(fileSystem, delegate);
-
-  /// Returns a file with the same file system as this entity but backed
-  /// by the specified delegate file.
-  @protected
-  File wrapFile(io.File delegate) => RecordingFile(fileSystem, delegate);
-
-  /// Returns a link with the same file system as this entity but backed
-  /// by the specified delegate link.
-  @protected
-  Link wrapLink(io.Link delegate) => RecordingLink(fileSystem, delegate);
-
-  Future<T> _rename(String newPath) => delegate
-      .rename(newPath)
-      .then((io.FileSystemEntity entity) => wrap(entity as T));
-
-  T _renameSync(String newPath) => wrap(delegate.renameSync(newPath) as T);
-
-  Future<T> _delete({bool recursive = false}) => delegate
-      .delete(recursive: recursive)
-      .then((io.FileSystemEntity entity) => wrap(entity as T));
-
-  T _getAbsolute() => wrap(delegate.absolute as T);
-
-  Directory _getParent() => wrapDirectory(delegate.parent);
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_io_sink.dart b/packages/file/lib/src/backends/record_replay/recording_io_sink.dart
deleted file mode 100644
index 1925018..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_io_sink.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'common.dart';
-import 'mutable_recording.dart';
-import 'recording_file_system.dart';
-import 'recording_proxy_mixin.dart';
-
-/// [IOSink] implementation that records all invocation activity to its file
-/// system's recording.
-class RecordingIOSink extends Object
-    with RecordingProxyMixin
-    implements IOSink {
-  /// Creates a new `RecordingIOSink`.
-  RecordingIOSink(this.fileSystem, this.delegate) {
-    methods.addAll(<Symbol, Function>{
-      #add: delegate.add,
-      #write: delegate.write,
-      #writeAll: delegate.writeAll,
-      #writeln: delegate.writeln,
-      #writeCharCode: delegate.writeCharCode,
-      #addError: delegate.addError,
-      #addStream: delegate.addStream,
-      #flush: delegate.flush,
-      #close: delegate.close,
-    });
-
-    properties.addAll(<Symbol, Function>{
-      #encoding: () => delegate.encoding,
-      const Symbol('encoding='): _setEncoding,
-      #done: () => delegate.done,
-    });
-  }
-
-  /// The file system that owns this sink.
-  final RecordingFileSystem fileSystem;
-
-  /// The sink to which this sink delegates its functionality while recording.
-  final IOSink delegate;
-
-  /// A unique entity id.
-  final int uid = newUid();
-
-  @override
-  String get identifier => '$runtimeType@$uid';
-
-  @override
-  MutableRecording get recording => fileSystem.recording as MutableRecording;
-
-  @override
-  Stopwatch get stopwatch => fileSystem.stopwatch;
-
-  void _setEncoding(Encoding value) {
-    delegate.encoding = value;
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_link.dart b/packages/file/lib/src/backends/record_replay/recording_link.dart
deleted file mode 100644
index 01954b9..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_link.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:file/file.dart';
-import 'package:file/src/io.dart' as io;
-
-import 'recording_file_system.dart';
-import 'recording_file_system_entity.dart';
-
-/// [Link] implementation that records all invocation activity to its file
-/// system's recording.
-class RecordingLink extends RecordingFileSystemEntity<Link> implements Link {
-  /// Creates a new `RecordingLink`.
-  RecordingLink(RecordingFileSystem fileSystem, io.Link delegate)
-      : super(fileSystem as RecordingFileSystemImpl, delegate as Link) {
-    methods.addAll(<Symbol, Function>{
-      #create: _create,
-      #createSync: delegate.createSync,
-      #update: _update,
-      #updateSync: delegate.updateSync,
-      #target: delegate.target,
-      #targetSync: delegate.targetSync,
-    });
-  }
-
-  @override
-  Link wrap(Link delegate) => super.wrap(delegate) ?? wrapLink(delegate);
-
-  Future<Link> _create(String target, {bool recursive = false}) =>
-      delegate.create(target, recursive: recursive).then(wrap);
-
-  Future<Link> _update(String target) => delegate.update(target).then(wrap);
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_proxy_mixin.dart b/packages/file/lib/src/backends/record_replay/recording_proxy_mixin.dart
deleted file mode 100644
index 08f92da..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_proxy_mixin.dart
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'package:file/file.dart';
-import 'package:file/src/backends/memory/node.dart';
-
-import 'package:meta/meta.dart';
-
-import 'common.dart';
-import 'events.dart';
-import 'mutable_recording.dart';
-import 'proxy.dart';
-import 'result_reference.dart';
-
-/// Mixin that enables recording of property accesses, property mutations, and
-/// method invocations.
-///
-/// This class uses `noSuchMethod` to record a well-defined set of invocations
-/// (including property gets and sets) on an object before passing the
-/// invocation on to a delegate. Subclasses wire this up by doing the following:
-///
-///   - Populate the list of method invocations to record in the [methods] map.
-///   - Populate the list of property invocations to record in the [properties]
-///     map. The symbol name for getters should be the property name, and the
-///     symbol name for setters should be the property name immediately
-///     followed by an equals sign (e.g. `propertyName=`).
-///   - Do not implement a concrete getter, setter, or method that you wish to
-///     record, as doing so will circumvent the machinery that this mixin uses
-///     (`noSuchMethod`) to record invocations.
-///
-/// **Example use**:
-///
-///     abstract class Foo {
-///       void sampleMethod();
-///
-///       int sampleProperty;
-///     }
-///
-///     class RecordingFoo extends RecordingProxyMixin implements Foo {
-///       final Foo delegate;
-///
-///       RecordingFoo(this.delegate) {
-///         methods.addAll(<Symbol, Function>{
-///           #sampleMethod: delegate.sampleMethod,
-///         });
-///
-///         properties.addAll(<Symbol, Function>{
-///           #sampleProperty: () => delegate.sampleProperty,
-///           const Symbol('sampleProperty='): (int value) {
-///             delegate.sampleProperty = value;
-///           },
-///         });
-///       }
-///     }
-///
-/// **Behavioral notes**:
-///
-/// Methods that return [Future]s will not be recorded until the future
-/// completes.
-///
-/// Methods that return [Stream]s will be recorded immediately, but their
-/// return values will be recorded as a [List] that will grow as the stream
-/// produces data.
-mixin RecordingProxyMixin on Object implements ProxyObject, ReplayAware {
-  /// Maps method names to delegate functions.
-  ///
-  /// Invocations of methods listed in this map will be recorded after
-  /// invoking the underlying delegate function.
-  @protected
-  final Map<Symbol, Function> methods = <Symbol, Function>{};
-
-  /// Maps property getter and setter names to delegate functions.
-  ///
-  /// Access and mutation of properties listed in this map will be recorded
-  /// after invoking the underlying delegate function.
-  ///
-  /// The keys for property getters are the simple property names, whereas the
-  /// keys for property setters are the property names followed by an equals
-  /// sign (e.g. `propertyName=`).
-  @protected
-  final Map<Symbol, Function> properties = <Symbol, Function>{};
-
-  /// The object to which invocation events will be recorded.
-  @protected
-  MutableRecording get recording;
-
-  /// The stopwatch used to record invocation timestamps.
-  @protected
-  Stopwatch get stopwatch;
-
-  /// Handles invocations for which there is no concrete implementation
-  /// function.
-  ///
-  /// For invocations that have matching entries in [methods] (for method
-  /// invocations) or [properties] (for property access and mutation), this
-  /// will record the invocation in [recording] after invoking the underlying
-  /// delegate method. All other invocations will throw a [NoSuchMethodError].
-  @override
-  dynamic noSuchMethod(Invocation invocation) {
-    Symbol name = invocation.memberName;
-    List<dynamic> args = invocation.positionalArguments;
-    Map<Symbol, dynamic> namedArgs = invocation.namedArguments;
-    Function method = invocation.isAccessor ? properties[name] : methods[name];
-    int time = stopwatch.elapsedMilliseconds;
-
-    if (method == null) {
-      // No delegate function generally means that there truly is no such
-      // method on this object. The exception is when the invocation represents
-      // a getter on a method, in which case we return a method proxy that,
-      // when invoked, will perform the desired recording.
-      return invocation.isGetter && methods[name] != null
-          ? MethodProxy(this, name)
-          : super.noSuchMethod(invocation);
-    }
-
-    InvocationEvent<dynamic> createEvent({dynamic result, dynamic error}) {
-      if (invocation.isGetter) {
-        return LivePropertyGetEvent<dynamic>(this, name, result, error, time);
-      } else if (invocation.isSetter) {
-        return LivePropertySetEvent<dynamic>(this, name, args[0], error, time);
-      } else {
-        return LiveMethodEvent<dynamic>(
-            this, name, args, namedArgs, result, error, time);
-      }
-    }
-
-    // Invoke the configured delegate method, recording an error if one occurs.
-    dynamic value;
-    try {
-      value = Function.apply(method, args, namedArgs);
-    } catch (error) {
-      recording.add(createEvent(error: error) as LiveInvocationEvent<dynamic>);
-      rethrow;
-    }
-
-    // Wrap Future and Stream results so that we record their values as they
-    // become available.
-    // We have to instantiate the correct type of StreamReference or
-    // FutureReference, so that types are not lost when we unwrap the references
-    // afterward.
-    if (value is Stream<FileSystemEntity>) {
-      value =
-          StreamReference<FileSystemEntity>(value as Stream<FileSystemEntity>);
-    } else if (value is Stream<String>) {
-      value = StreamReference<String>(value as Stream<String>);
-    } else if (value is Stream) {
-      throw UnimplementedError(
-          'Cannot record method with return type ${value.runtimeType}');
-    } else if (value is Future<bool>) {
-      value = FutureReference<bool>(value as Future<bool>);
-    } else if (value is Future<Directory>) {
-      value = FutureReference<Directory>(value as Future<Directory>);
-    } else if (value is Future<File>) {
-      value = FutureReference<File>(value as Future<File>);
-    } else if (value is Future<FileNode>) {
-      value = FutureReference<FileNode>(value as Future<FileNode>);
-    } else if (value is Future<FileStat>) {
-      value = FutureReference<FileStat>(value as Future<FileStat>);
-    } else if (value is Future<Link>) {
-      value = FutureReference<Link>(value as Future<Link>);
-    } else if (value is Future<FileSystemEntity>) {
-      value =
-          FutureReference<FileSystemEntity>(value as Future<FileSystemEntity>);
-    } else if (value is Future<FileSystemEntityType>) {
-      value = FutureReference<FileSystemEntityType>(
-          value as Future<FileSystemEntityType>);
-    } else if (value is Future<String>) {
-      value = FutureReference<String>(value as Future<String>);
-    } else if (value is Future<RandomAccessFile>) {
-      value =
-          FutureReference<RandomAccessFile>(value as Future<RandomAccessFile>);
-    } else if (value is Future<void>) {
-      value = FutureReference<void>(value as Future<void>);
-    }
-
-    // Record the invocation event associated with this invocation.
-    recording.add(createEvent(result: value) as LiveInvocationEvent<dynamic>);
-
-    // Unwrap any result references before returning to the caller.
-    dynamic result = value;
-    while (result is ResultReference) {
-      result = result.value;
-    }
-    return result;
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/recording_random_access_file.dart b/packages/file/lib/src/backends/record_replay/recording_random_access_file.dart
deleted file mode 100644
index f5ba461..0000000
--- a/packages/file/lib/src/backends/record_replay/recording_random_access_file.dart
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'common.dart';
-import 'mutable_recording.dart';
-import 'recording_file_system.dart';
-import 'recording_proxy_mixin.dart';
-
-/// [RandomAccessFile] implementation that records all invocation activity to
-/// its file system's recording.
-class RecordingRandomAccessFile extends Object
-    with RecordingProxyMixin
-    implements RandomAccessFile {
-  /// Creates a new `RecordingRandomAccessFile`.
-  RecordingRandomAccessFile(this.fileSystem, this.delegate) {
-    methods.addAll(<Symbol, Function>{
-      #close: _close,
-      #closeSync: delegate.closeSync,
-      #readByte: delegate.readByte,
-      #readByteSync: delegate.readByteSync,
-      #read: delegate.read,
-      #readSync: delegate.readSync,
-      #readInto: delegate.readInto,
-      #readIntoSync: delegate.readIntoSync,
-      #writeByte: _writeByte,
-      #writeByteSync: delegate.writeByteSync,
-      #writeFrom: _writeFrom,
-      #writeFromSync: delegate.writeFromSync,
-      #writeString: _writeString,
-      #writeStringSync: delegate.writeStringSync,
-      #position: delegate.position,
-      #positionSync: delegate.positionSync,
-      #setPosition: _setPosition,
-      #setPositionSync: delegate.setPositionSync,
-      #truncate: _truncate,
-      #truncateSync: delegate.truncateSync,
-      #length: delegate.length,
-      #lengthSync: delegate.lengthSync,
-      #flush: _flush,
-      #flushSync: delegate.flushSync,
-      #lock: _lock,
-      #lockSync: delegate.lockSync,
-      #unlock: _unlock,
-      #unlockSync: delegate.unlockSync,
-    });
-
-    properties.addAll(<Symbol, Function>{
-      #path: () => delegate.path,
-    });
-  }
-
-  /// The file system that owns this random access file.
-  final RecordingFileSystem fileSystem;
-
-  /// The random access file to which this random access file delegates its
-  /// functionality while recording.
-  final RandomAccessFile delegate;
-
-  /// A unique entity id.
-  final int uid = newUid();
-
-  @override
-  String get identifier => '$runtimeType@$uid';
-
-  @override
-  MutableRecording get recording => fileSystem.recording as MutableRecording;
-
-  @override
-  Stopwatch get stopwatch => fileSystem.stopwatch;
-
-  RandomAccessFile _wrap(RandomAccessFile raw) =>
-      raw == delegate ? this : RecordingRandomAccessFile(fileSystem, raw);
-
-  Future<void> _close() => delegate.close();
-
-  Future<RandomAccessFile> _writeByte(int value) =>
-      delegate.writeByte(value).then(_wrap);
-
-  Future<RandomAccessFile> _writeFrom(List<int> buffer,
-          [int start = 0, int end]) =>
-      delegate.writeFrom(buffer, start, end).then(_wrap);
-
-  Future<RandomAccessFile> _writeString(String string,
-          {Encoding encoding = utf8}) =>
-      delegate.writeString(string, encoding: encoding).then(_wrap);
-
-  Future<RandomAccessFile> _setPosition(int position) =>
-      delegate.setPosition(position).then(_wrap);
-
-  Future<RandomAccessFile> _truncate(int length) =>
-      delegate.truncate(length).then(_wrap);
-
-  Future<RandomAccessFile> _flush() => delegate.flush().then(_wrap);
-
-  Future<RandomAccessFile> _lock(
-          [FileLock mode = FileLock.exclusive, int start = 0, int end = -1]) =>
-      delegate.lock(mode, start, end).then(_wrap);
-
-  Future<RandomAccessFile> _unlock([int start = 0, int end = -1]) =>
-      delegate.unlock(start, end).then(_wrap);
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_directory.dart b/packages/file/lib/src/backends/record_replay/replay_directory.dart
deleted file mode 100644
index f0b1add..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_directory.dart
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_file_system_entity.dart';
-
-/// [Directory] implementation that replays all invocation activity from a
-/// prior recording.
-class ReplayDirectory extends ReplayFileSystemEntity implements Directory {
-  /// Creates a new `ReplayDirectory`.
-  ReplayDirectory(ReplayFileSystemImpl fileSystem, String identifier)
-      : super(fileSystem, identifier) {
-    Converter<String, Directory> reviveDirectory = ReviveDirectory(fileSystem);
-    Converter<String, Future<Directory>> reviveFutureDirectory =
-        reviveDirectory.fuse(const ToFuture<Directory>());
-    Converter<String, FileSystemEntity> reviveEntity =
-        ReviveFileSystemEntity(fileSystem);
-    Converter<List<dynamic>, List<String>> dynamicToString =
-        const CastList<dynamic, String>();
-    Converter<List<dynamic>, List<FileSystemEntity>> reviveEntities =
-        dynamicToString.fuse<List<FileSystemEntity>>(
-            ConvertElements<String, FileSystemEntity>(reviveEntity));
-    Converter<List<dynamic>, Stream<FileSystemEntity>> reviveEntitiesAsStream =
-        reviveEntities
-            .fuse<Stream<FileSystemEntity>>(const ToStream<FileSystemEntity>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #rename: reviveFutureDirectory,
-      #renameSync: reviveDirectory,
-      #delete: reviveFutureDirectory,
-      #create: reviveFutureDirectory,
-      #createSync: const Passthrough<Null>(),
-      #createTemp: reviveFutureDirectory,
-      #createTempSync: reviveDirectory,
-      #list: reviveEntitiesAsStream,
-      #listSync: reviveEntities,
-      #childDirectory: reviveDirectory,
-      #childFile: ReviveFile(fileSystem),
-      #childLink: ReviveLink(fileSystem),
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #absolute: reviveDirectory,
-    });
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_file.dart b/packages/file/lib/src/backends/record_replay/replay_file.dart
deleted file mode 100644
index 8eaa790..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_file.dart
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_file_system_entity.dart';
-
-/// [File] implementation that replays all invocation activity from a prior
-/// recording.
-class ReplayFile extends ReplayFileSystemEntity implements File {
-  /// Creates a new `ReplayFile`.
-  ReplayFile(ReplayFileSystemImpl fileSystem, String identifier)
-      : super(fileSystem, identifier) {
-    Converter<String, File> reviveFile = ReviveFile(fileSystem);
-    Converter<String, Future<File>> reviveFileAsFuture =
-        reviveFile.fuse(const ToFuture<File>());
-    Converter<String, Uint8List> blobToBytes = BlobToBytes(fileSystem);
-    Converter<String, Future<Uint8List>> blobToBytesFuture =
-        blobToBytes.fuse(const ToFuture<Uint8List>());
-    Converter<String, String> blobToString =
-        blobToBytes.cast<String, List<int>>().fuse(utf8.decoder);
-    Converter<String, Future<String>> blobToStringFuture =
-        blobToString.fuse(const ToFuture<String>());
-    Converter<String, RandomAccessFile> reviveRandomAccessFile =
-        ReviveRandomAccessFile(fileSystem);
-    Converter<String, Future<RandomAccessFile>> reviveRandomAccessFileFuture =
-        reviveRandomAccessFile.fuse(const ToFuture<RandomAccessFile>());
-    Converter<String, List<String>> lineSplitter =
-        const LineSplitterConverter();
-    Converter<String, List<String>> blobToLines =
-        blobToString.fuse(lineSplitter);
-    Converter<String, Future<List<String>>> blobToLinesFuture =
-        blobToLines.fuse(const ToFuture<List<String>>());
-    Converter<String, Stream<Uint8List>> blobToByteStream = blobToBytes
-        .fuse(const Listify<Uint8List>())
-        .fuse(const ToStream<Uint8List>());
-    Converter<int, Future<DateTime>> reviveDateTime =
-        DateTimeCodec.deserialize.fuse(const ToFuture<DateTime>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #rename: reviveFileAsFuture,
-      #renameSync: reviveFile,
-      #delete: reviveFileAsFuture,
-      #create: reviveFileAsFuture,
-      #createSync: const Passthrough<Null>(),
-      #copy: reviveFileAsFuture,
-      #copySync: reviveFile,
-      #length: const ToFuture<int>(),
-      #lengthSync: const Passthrough<int>(),
-      #lastAccessed: reviveDateTime,
-      #lastAccessedSync: DateTimeCodec.deserialize,
-      #setLastAccessed: const ToFuture<dynamic>(),
-      #setLastAccessedSync: const Passthrough<Null>(),
-      #lastModified: reviveDateTime,
-      #lastModifiedSync: DateTimeCodec.deserialize,
-      #setLastModified: const ToFuture<dynamic>(),
-      #setLastModifiedSync: const Passthrough<Null>(),
-      #open: reviveRandomAccessFileFuture,
-      #openSync: reviveRandomAccessFile,
-      #openRead: blobToByteStream,
-      #openWrite: ReviveIOSink(fileSystem),
-      #readAsBytes: blobToBytesFuture,
-      #readAsBytesSync: blobToBytes,
-      #readAsString: blobToStringFuture,
-      #readAsStringSync: blobToString,
-      #readAsLines: blobToLinesFuture,
-      #readAsLinesSync: blobToLines,
-      #writeAsBytes: reviveFileAsFuture,
-      #writeAsBytesSync: const Passthrough<Null>(),
-      #writeAsString: reviveFileAsFuture,
-      #writeAsStringSync: const Passthrough<Null>(),
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #absolute: reviveFile,
-    });
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_file_stat.dart b/packages/file/lib/src/backends/record_replay/replay_file_stat.dart
deleted file mode 100644
index 497d403..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_file_stat.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-
-/// [FileStat] implementation that derives its properties from a recorded
-/// invocation event.
-class ReplayFileStat implements FileStat {
-  /// Creates a new `ReplayFileStat` that will derive its properties from the
-  /// specified [data].
-  ReplayFileStat(Map<String, dynamic> data) : _data = data;
-
-  final Map<String, dynamic> _data;
-
-  @override
-  DateTime get changed =>
-      DateTimeCodec.deserialize.convert(_data['changed'] as int);
-
-  @override
-  DateTime get modified =>
-      DateTimeCodec.deserialize.convert(_data['modified'] as int);
-
-  @override
-  DateTime get accessed =>
-      DateTimeCodec.deserialize.convert(_data['accessed'] as int);
-
-  @override
-  FileSystemEntityType get type =>
-      EntityTypeCodec.deserialize.convert(_data['type'] as String);
-
-  @override
-  int get mode => _data['mode'] as int;
-
-  @override
-  int get size => _data['size'] as int;
-
-  @override
-  String modeString() => _data['modeString'] as String;
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_file_system.dart b/packages/file/lib/src/backends/record_replay/replay_file_system.dart
deleted file mode 100644
index 35b12c4..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_file_system.dart
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-import 'package:meta/meta.dart';
-
-import 'codecs.dart';
-import 'common.dart';
-import 'errors.dart';
-import 'recording_file_system.dart';
-import 'replay_proxy_mixin.dart';
-
-/// A file system that replays invocations from a prior recording for use
-/// in tests.
-///
-/// This will replay all invocations (methods, property getters, and property
-/// setters) that occur on it, based on an opaque recording that was generated
-/// in [RecordingFileSystem]. All activity in the [File], [Directory], [Link],
-/// [IOSink], and [RandomAccessFile] instances returned from this API will also
-/// be replayed from the same recording.
-///
-/// Once an invocation has been replayed once, it is marked as such and will
-/// not be eligible for further replay. If an eligible invocation cannot be
-/// found that matches an incoming invocation, a [NoMatchingInvocationError]
-/// will be thrown.
-///
-/// This class is intended for use in tests, where you would otherwise have to
-/// set up complex mocks or fake file systems. With this class, the process is
-/// as follows:
-///
-///   - You record the file system activity during a real run of your program
-///     by injecting a `RecordingFileSystem` that delegates to your real file
-///     system.
-///   - You serialize that recording to disk as your program finishes.
-///   - You use that recording in tests to create a mock file system that knows
-///     how to respond to the exact invocations your program makes. Any
-///     invocations that aren't in the recording will throw, and you can make
-///     assertions in your tests about which methods were invoked and in what
-///     order.
-///
-/// *Implementation note*: this class uses [noSuchMethod] to dynamically handle
-/// invocations. As a result, method references on objects herein will not pass
-/// `is` checks or checked-mode checks on type. For example:
-///
-/// ```dart
-/// typedef FileStat StatSync(String path);
-/// FileSystem fs = ReplayFileSystem(directory);
-///
-/// StatSync method = fs.statSync;     // Will fail in checked-mode
-/// fs.statSync is StatSync            // Will return false
-/// fs.statSync is Function            // Will return false
-///
-/// dynamic method2 = fs.statSync;     // OK
-/// FileStat stat = method2('/path');  // OK
-/// ```
-///
-/// See also:
-///   - [RecordingFileSystem]
-abstract class ReplayFileSystem extends FileSystem {
-  /// Creates a new `ReplayFileSystem`.
-  ///
-  /// Recording data will be loaded from the specified [recording] location.
-  /// This location must have been created by [RecordingFileSystem], or an
-  /// [ArgumentError] will be thrown.
-  factory ReplayFileSystem({
-    @required Directory recording,
-  }) {
-    String dirname = recording.path;
-    String path = recording.fileSystem.path.join(dirname, kManifestName);
-    File manifestFile = recording.fileSystem.file(path);
-    if (!manifestFile.existsSync()) {
-      throw ArgumentError('Not a valid recording directory: $dirname');
-    }
-    List<Map<String, dynamic>> manifest = (const JsonDecoder()
-            .convert(manifestFile.readAsStringSync()) as List<dynamic>)
-        .cast<Map<String, dynamic>>();
-    return ReplayFileSystemImpl(recording, manifest);
-  }
-}
-
-/// Non-exported implementation class for `ReplayFileSystem`.
-class ReplayFileSystemImpl extends FileSystem
-    with ReplayProxyMixin
-    implements ReplayFileSystem, ReplayAware {
-  /// Creates a new `ReplayFileSystemImpl`.
-  ReplayFileSystemImpl(this.recording, this.manifest) {
-    Converter<String, Directory> reviveDirectory = ReviveDirectory(this);
-    Converter<String, Future<FileSystemEntityType>> reviveEntityFuture =
-        EntityTypeCodec.deserialize
-            .fuse(const ToFuture<FileSystemEntityType>());
-    Converter<Map<String, Object>, Future<FileStat>> reviveFileStatFuture =
-        FileStatCodec.deserialize.fuse(const ToFuture<FileStat>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #directory: reviveDirectory,
-      #file: ReviveFile(this),
-      #link: ReviveLink(this),
-      #stat: reviveFileStatFuture,
-      #statSync: FileStatCodec.deserialize,
-      #identical: const ToFuture<bool>(),
-      #identicalSync: const Passthrough<bool>(),
-      #type: reviveEntityFuture,
-      #typeSync: EntityTypeCodec.deserialize,
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #path: PathContextCodec.deserialize,
-      #systemTempDirectory: reviveDirectory,
-      #currentDirectory: reviveDirectory,
-      const Symbol('currentDirectory='): const Passthrough<Null>(),
-      #isWatchSupported: const Passthrough<bool>(),
-    });
-  }
-
-  /// The location of the recording that's driving this file system
-  final Directory recording;
-
-  @override
-  String get identifier => kFileSystemEncodedValue;
-
-  @override
-  final List<Map<String, dynamic>> manifest;
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_file_system_entity.dart b/packages/file/lib/src/backends/record_replay/replay_file_system_entity.dart
deleted file mode 100644
index 1f32f8e..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_file_system_entity.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_proxy_mixin.dart';
-
-/// [FileSystemEntity] implementation that replays all invocation activity
-/// from a prior recording.
-abstract class ReplayFileSystemEntity extends Object
-    with ReplayProxyMixin
-    implements FileSystemEntity {
-  /// Creates a new `ReplayFileSystemEntity`.
-  ReplayFileSystemEntity(this.fileSystem, this.identifier) {
-    Converter<List<Map<String, Object>>, List<FileSystemEvent>> toEvents =
-        const ConvertElements<Map<String, Object>, FileSystemEvent>(
-            FileSystemEventCodec.deserialize);
-    Converter<List<Map<String, Object>>, Stream<FileSystemEvent>>
-        toEventStream = toEvents.fuse(const ToStream<FileSystemEvent>());
-    Converter<Map<String, Object>, Future<FileStat>> reviveFileStatFuture =
-        FileStatCodec.deserialize.fuse(const ToFuture<FileStat>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #exists: const ToFuture<bool>(),
-      #existsSync: const Passthrough<bool>(),
-      #resolveSymbolicLinks: const ToFuture<String>(),
-      #resolveSymbolicLinksSync: const Passthrough<String>(),
-      #stat: reviveFileStatFuture,
-      #statSync: FileStatCodec.deserialize,
-      #deleteSync: const Passthrough<Null>(),
-      #watch: toEventStream,
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #path: const Passthrough<String>(),
-      #uri: UriCodec.deserialize,
-      #isAbsolute: const Passthrough<bool>(),
-      #parent: ReviveDirectory(fileSystem),
-      #basename: const Passthrough<String>(),
-      #dirname: const Passthrough<String>(),
-    });
-  }
-
-  @override
-  final ReplayFileSystemImpl fileSystem;
-
-  @override
-  final String identifier;
-
-  @override
-  List<Map<String, dynamic>> get manifest => fileSystem.manifest;
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_io_sink.dart b/packages/file/lib/src/backends/record_replay/replay_io_sink.dart
deleted file mode 100644
index 4dbbd4d..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_io_sink.dart
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_proxy_mixin.dart';
-
-/// [IOSink] implementation that replays all invocation activity from a prior
-/// recording.
-class ReplayIOSink extends Object with ReplayProxyMixin implements IOSink {
-  /// Creates a new [ReplayIOSink].
-  ReplayIOSink(this._fileSystem, this.identifier) {
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #add: const Passthrough<Null>(),
-      #write: const Passthrough<Null>(),
-      #writeAll: const Passthrough<Null>(),
-      #writeln: const Passthrough<Null>(),
-      #writeCharCode: const Passthrough<Null>(),
-      #addError: const Passthrough<Null>(),
-      #addStream: const ToFuture<dynamic>(),
-      #flush: const ToFuture<dynamic>(),
-      #close: const ToFuture<dynamic>(),
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #encoding: EncodingCodec.deserialize,
-      const Symbol('encoding='): const Passthrough<Null>(),
-      #done: const ToFuture<dynamic>(),
-    });
-  }
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  final String identifier;
-
-  @override
-  List<Map<String, dynamic>> get manifest => _fileSystem.manifest;
-
-  @override
-  dynamic onResult(Invocation invocation, dynamic result) {
-    if (invocation.memberName == #addStream) {
-      Stream<List<int>> stream =
-          invocation.positionalArguments.first as Stream<List<int>>;
-      Future<dynamic> future = result as Future<dynamic>;
-      return future.then<void>(stream.drain);
-    }
-    return result;
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_link.dart b/packages/file/lib/src/backends/record_replay/replay_link.dart
deleted file mode 100644
index 74deb53..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_link.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_file_system_entity.dart';
-
-/// [Link] implementation that replays all invocation activity from a prior
-/// recording.
-class ReplayLink extends ReplayFileSystemEntity implements Link {
-  /// Creates a new `ReplayLink`.
-  ReplayLink(ReplayFileSystemImpl fileSystem, String identifier)
-      : super(fileSystem, identifier) {
-    Converter<String, Link> reviveLink = ReviveLink(fileSystem);
-    Converter<String, Future<Link>> reviveLinkAsFuture =
-        reviveLink.fuse(const ToFuture<Link>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #rename: reviveLinkAsFuture,
-      #renameSync: reviveLink,
-      #delete: reviveLinkAsFuture,
-      #create: reviveLinkAsFuture,
-      #createSync: const Passthrough<Null>(),
-      #update: reviveLinkAsFuture,
-      #updateSync: const Passthrough<Null>(),
-      #target: const ToFuture<String>(),
-      #targetSync: const Passthrough<String>(),
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #absolute: reviveLink,
-    });
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_proxy_mixin.dart b/packages/file/lib/src/backends/record_replay/replay_proxy_mixin.dart
deleted file mode 100644
index d501ab3..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_proxy_mixin.dart
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-
-import 'package:meta/meta.dart';
-
-import 'codecs.dart';
-import 'common.dart';
-import 'errors.dart';
-import 'proxy.dart';
-
-typedef _InvocationMatcher = bool Function(Map<String, dynamic> entry);
-
-/// Used to record the order in which invocations were replayed.
-///
-/// Tests can later check expectations about the order in which invocations
-/// were replayed vis-a-vis the order in which they were recorded.
-int _nextOrdinal = 0;
-
-/// Mixin that enables replaying of property accesses, property mutations, and
-/// method invocations from a prior recording.
-///
-/// This class uses `noSuchMethod` to replay a well-defined set of invocations
-/// (including property gets and sets) on an object. Subclasses wire this up by
-/// doing the following:
-///
-///   - Populate the list of method invocations to replay in the [methods] map.
-///   - Populate the list of property invocations to replay in the [properties]
-///     map. The symbol name for getters should be the property name, and the
-///     symbol name for setters should be the property name immediately
-///     followed by an equals sign (e.g. `propertyName=`).
-///   - Do not implement a concrete getter, setter, or method that you wish to
-///     replay, as doing so will circumvent the machinery that this mixin uses
-///     (`noSuchMethod`) to replay invocations.
-///
-/// **Example use**:
-///
-///     abstract class Foo {
-///       ComplexObject sampleMethod();
-///
-///       Foo sampleParent;
-///     }
-///
-///     class ReplayFoo extends Object with ReplayProxyMixin implements Foo {
-///       final List<Map<String, dynamic>> manifest;
-///       final String identifier;
-///
-///       ReplayFoo(this.manifest, this.identifier) {
-///         methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-///           #sampleMethod: complexObjectReviver,
-///         });
-///
-///         properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-///           #sampleParent: fooReviver,
-///           const Symbol('sampleParent='): passthroughReviver,
-///         });
-///       }
-///     }
-mixin ReplayProxyMixin on Object implements ProxyObject, ReplayAware {
-  /// Maps method names to [Converter]s that will revive result values.
-  ///
-  /// Invocations of methods listed in this map will be replayed by looking for
-  /// matching invocations in the [manifest] and reviving the invocation return
-  /// value using the [Converter] found in this map.
-  @protected
-  final Map<Symbol, Converter<dynamic, dynamic>> methods =
-      <Symbol, Converter<dynamic, dynamic>>{};
-
-  /// Maps property getter and setter names to [Converter]s that will revive
-  /// result values.
-  ///
-  /// Access and mutation of properties listed in this map will be replayed
-  /// by looking for matching property accesses in the [manifest] and reviving
-  /// the invocation return value using the [Converter] found in this map.
-  ///
-  /// The keys for property getters are the simple property names, whereas the
-  /// keys for property setters are the property names followed by an equals
-  /// sign (e.g. `propertyName=`).
-  @protected
-  final Map<Symbol, Converter<dynamic, dynamic>> properties =
-      <Symbol, Converter<dynamic, dynamic>>{};
-
-  /// The manifest of recorded invocation events.
-  ///
-  /// When invocations are received on this object, we will attempt find a
-  /// matching invocation in this manifest to perform the replay. If no such
-  /// invocation is found (or if it has already been replayed), the caller will
-  /// receive a [NoMatchingInvocationError].
-  ///
-  /// This manifest exists as `MANIFEST.txt` in a recording directory.
-  @protected
-  List<Map<String, dynamic>> get manifest;
-
-  /// Protected method for subclasses to be notified when an invocation has
-  /// been successfully replayed, and the result is about to be returned to
-  /// the caller.
-  ///
-  /// Returns the value that is to be returned to the caller. The default
-  /// implementation returns [result] (replayed from the recording); subclasses
-  /// may override this method to alter the result that's returned to the
-  /// caller.
-  @protected
-  dynamic onResult(Invocation invocation, dynamic result) => result;
-
-  @override
-  dynamic noSuchMethod(Invocation invocation) {
-    Symbol name = invocation.memberName;
-    Converter<dynamic, dynamic> reviver =
-        invocation.isAccessor ? properties[name] : methods[name];
-
-    if (reviver == null) {
-      // No reviver generally means that there truly is no such method on
-      // this object. The exception is when the invocation represents a getter
-      // on a method, in which case we return a method proxy that, when
-      // invoked, will replay the desired invocation.
-      return invocation.isGetter && methods[name] != null
-          ? MethodProxy(this, name)
-          : super.noSuchMethod(invocation);
-    }
-
-    Map<String, dynamic> entry = _nextEvent(invocation);
-    if (entry == null) {
-      throw NoMatchingInvocationError(invocation);
-    }
-    entry[kManifestOrdinalKey] = _nextOrdinal++;
-
-    dynamic error = entry[kManifestErrorKey];
-    if (error != null) {
-      throw const ToError().convert(error);
-    }
-    dynamic result = reviver.convert(entry[kManifestResultKey]);
-    result = onResult(invocation, result);
-    return result;
-  }
-
-  /// Finds the next available invocation event in the [manifest] that matches
-  /// the specified [invocation].
-  Map<String, dynamic> _nextEvent(Invocation invocation) {
-    _InvocationMatcher matches = _getMatcher(invocation);
-    return manifest.firstWhere((Map<String, dynamic> entry) {
-      return entry[kManifestOrdinalKey] == null && matches(entry);
-    }, orElse: () => null);
-  }
-
-  _InvocationMatcher _getMatcher(Invocation invocation) {
-    String name = getSymbolName(invocation.memberName);
-    List<dynamic> args =
-        encode(invocation.positionalArguments) as List<dynamic>;
-    Map<String, dynamic> namedArgs =
-        encode(invocation.namedArguments) as Map<String, dynamic>;
-
-    if (invocation.isGetter) {
-      return (Map<String, dynamic> entry) =>
-          entry[kManifestTypeKey] == kGetType &&
-          entry[kManifestPropertyKey] == name &&
-          entry[kManifestObjectKey] == identifier;
-    } else if (invocation.isSetter) {
-      return (Map<String, dynamic> entry) =>
-          entry[kManifestTypeKey] == kSetType &&
-          entry[kManifestPropertyKey] == name &&
-          deeplyEqual(entry[kManifestValueKey], args[0]) &&
-          entry[kManifestObjectKey] == identifier;
-    } else {
-      return (Map<String, dynamic> entry) {
-        return entry[kManifestTypeKey] == kInvokeType &&
-            entry[kManifestMethodKey] == name &&
-            deeplyEqual(entry[kManifestPositionalArgumentsKey], args) &&
-            deeplyEqual(
-                _asNamedArgsType(
-                    entry[kManifestNamedArgumentsKey] as Map<String, dynamic>),
-                namedArgs) &&
-            entry[kManifestObjectKey] == identifier;
-      };
-    }
-  }
-
-  static Map<String, dynamic> _asNamedArgsType(Map<dynamic, dynamic> map) {
-    return Map<String, dynamic>.from(map);
-  }
-}
diff --git a/packages/file/lib/src/backends/record_replay/replay_random_access_file.dart b/packages/file/lib/src/backends/record_replay/replay_random_access_file.dart
deleted file mode 100644
index eb4d0cc..0000000
--- a/packages/file/lib/src/backends/record_replay/replay_random_access_file.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:file/file.dart';
-
-import 'codecs.dart';
-import 'replay_file_system.dart';
-import 'replay_proxy_mixin.dart';
-
-/// [RandomAccessFile] implementation that replays all invocation activity from a prior
-/// recording.
-class ReplayRandomAccessFile extends Object
-    with ReplayProxyMixin
-    implements RandomAccessFile {
-  /// Creates a new [ReplayRandomAccessFile].
-  ReplayRandomAccessFile(this._fileSystem, this.identifier) {
-    ToFuture<RandomAccessFile> toFuture = const ToFuture<RandomAccessFile>();
-    Converter<String, Future<RandomAccessFile>> reviveRandomAccessFileAsFuture =
-        ReviveRandomAccessFile(_fileSystem).fuse(toFuture);
-
-    Converter<List<dynamic>, Uint8List> reviveUint8List =
-        const CastList<dynamic, int>().fuse(const ToUint8List());
-    Converter<List<dynamic>, Future<Uint8List>> reviveUint8ListFuture =
-        reviveUint8List.fuse(const ToFuture<Uint8List>());
-
-    methods.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #close: reviveRandomAccessFileAsFuture,
-      #closeSync: const Passthrough<Null>(),
-      #readByte: const ToFuture<int>(),
-      #readByteSync: const Passthrough<int>(),
-      #read: reviveUint8ListFuture,
-      #readSync: reviveUint8List,
-      #readInto: const ToFuture<int>(),
-      #readIntoSync: const Passthrough<int>(),
-      #writeByte: reviveRandomAccessFileAsFuture,
-      #writeByteSync: const Passthrough<int>(),
-      #writeFrom: reviveRandomAccessFileAsFuture,
-      #writeFromSync: const Passthrough<Null>(),
-      #writeString: reviveRandomAccessFileAsFuture,
-      #writeStringSync: const Passthrough<Null>(),
-      #position: const ToFuture<int>(),
-      #positionSync: const Passthrough<int>(),
-      #setPosition: reviveRandomAccessFileAsFuture,
-      #setPositionSync: const Passthrough<Null>(),
-      #truncate: reviveRandomAccessFileAsFuture,
-      #truncateSync: const Passthrough<Null>(),
-      #length: const ToFuture<int>(),
-      #lengthSync: const Passthrough<int>(),
-      #flush: reviveRandomAccessFileAsFuture,
-      #flushSync: const Passthrough<Null>(),
-      #lock: reviveRandomAccessFileAsFuture,
-      #lockSync: const Passthrough<Null>(),
-      #unlock: reviveRandomAccessFileAsFuture,
-      #unlockSync: const Passthrough<Null>(),
-    });
-
-    properties.addAll(<Symbol, Converter<dynamic, dynamic>>{
-      #path: const Passthrough<String>(),
-    });
-  }
-
-  final ReplayFileSystemImpl _fileSystem;
-
-  @override
-  final String identifier;
-
-  @override
-  List<Map<String, dynamic>> get manifest => _fileSystem.manifest;
-}
diff --git a/packages/file/lib/src/backends/record_replay/result_reference.dart b/packages/file/lib/src/backends/record_replay/result_reference.dart
deleted file mode 100644
index 3228bce..0000000
--- a/packages/file/lib/src/backends/record_replay/result_reference.dart
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:meta/meta.dart';
-
-import 'codecs.dart';
-import 'events.dart';
-import 'recording_proxy_mixin.dart';
-
-/// Wraps a raw invocation return value for the purpose of recording.
-///
-/// This class is intended for use with [RecordingProxyMixin]. Mixin subclasses
-/// may configure a method or getter to return a [ResultReference] rather than
-/// a raw result, and:
-///
-///   - [RecordingProxyMixin] will automatically return the reference's [value]
-///     to callers (as if the mixin subclass had returned the raw value
-///     directly).
-///   - The recording's [InvocationEvent] will automatically record the
-///     reference's [recordedValue].
-///   - The recording's serialized value (written out during
-///     [LiveRecording.flush]) will automatically serialize the reference's
-///     [serializedValue].
-abstract class ResultReference<T> {
-  /// Creates a new `ResultReference`.
-  const ResultReference();
-
-  /// The raw value to return to callers of the method or getter.
-  T get value;
-
-  /// The value to record in the recording's [InvocationEvent].
-  dynamic get recordedValue;
-
-  /// A JSON-serializable representation of this result, suitable for
-  /// encoding in a recording manifest.
-  ///
-  /// The value of this property will be one of the JSON-native types: `num`,
-  /// `String`, `bool`, `Null`, `List`, or `Map`.
-  ///
-  /// This allows for method-specific encoding routines. Take, for example, the
-  /// case of a method that returns `List<int>`. This type is natively
-  /// serializable by `JSONEncoder`, so if the raw value were directly returned
-  /// from an invocation, the recording would happily serialize the result as
-  /// a list of integers. However, the method may want to serialize the return
-  /// value differently, such as by writing it to file (if it knows the list is
-  /// actually a byte array that was read from a file). In this case, the
-  /// method can return a `ResultReference` to the list, and it will have a
-  /// hook into the serialization process.
-  dynamic get serializedValue => encode(recordedValue);
-
-  /// A [Future] that completes when [value] has completed.
-  ///
-  /// If [value] is a [Future], this future will complete when [value] has
-  /// completed. If [value] is a [Stream], this future will complete when the
-  /// stream sends a "done" event. If value is neither a future nor a stream,
-  /// this future will complete immediately.
-  Future<void> get complete => Future<void>.value();
-}
-
-/// Wraps a future result.
-class FutureReference<T> extends ResultReference<Future<T>> {
-  /// Creates a new `FutureReference` that wraps the specified [future].
-  FutureReference(Future<T> future) : _future = future;
-
-  final Future<T> _future;
-  T _value;
-
-  bool get _isVoid => T == const _TypeLiteral<void>().type;
-
-  /// The future value to return to callers of the method or getter.
-  @override
-  Future<T> get value {
-    return _future.then(
-      (T value) {
-        if (_isVoid && value != null) {
-          throw StateError(
-              'Unexpected value in $runtimeType: ${_future.runtimeType}');
-        }
-        _value = value;
-        return value;
-      },
-      onError: (dynamic error) {
-        // TODO(tvolkert): Record errors
-        throw error;
-      },
-    );
-  }
-
-  /// The value returned by the completion of the future.
-  ///
-  /// If the future threw an error, this value will be `null`.
-  @override
-  T get recordedValue => _value;
-
-  @override
-  Future<void> get complete => value.catchError((dynamic _) {});
-}
-
-class _TypeLiteral<T> {
-  const _TypeLiteral();
-
-  Type get type => T;
-}
-
-/// Wraps a stream result.
-class StreamReference<T> extends ResultReference<Stream<T>> {
-  /// Creates a new `StreamReference` that wraps the specified [stream].
-  StreamReference(Stream<T> stream)
-      : _stream = stream,
-        _controller = stream.isBroadcast
-            ? StreamController<T>.broadcast()
-            : StreamController<T>() {
-    _controller.onListen = () {
-      assert(_subscription == null);
-      _subscription = _listenToStream();
-    };
-    _controller.onCancel = () async {
-      assert(_subscription != null);
-      await _subscription.cancel();
-      _subscription = null;
-    };
-    _controller.onPause = () {
-      assert(_subscription != null && !_subscription.isPaused);
-      _subscription.pause();
-    };
-    _controller.onResume = () {
-      assert(_subscription != null && _subscription.isPaused);
-      _subscription.resume();
-    };
-  }
-
-  final Stream<T> _stream;
-  final StreamController<T> _controller;
-  final Completer<void> _completer = Completer<void>();
-  final List<T> _data = <T>[];
-  StreamSubscription<T> _subscription;
-
-  StreamSubscription<T> _listenToStream() {
-    return _stream.listen(
-      (T element) {
-        _data.add(element);
-        onData(element);
-        _controller.add(element);
-      },
-      onError: (dynamic error, StackTrace stackTrace) {
-        // TODO(tvolkert): Record errors
-        _controller.addError(error, stackTrace);
-      },
-      onDone: () {
-        _completer.complete();
-        _controller.close();
-      },
-    );
-  }
-
-  /// Called when an event is received from the underlying delegate stream.
-  ///
-  /// Subclasses may override this method to be notified when events are
-  /// fired from the underlying stream.
-  @protected
-  void onData(T event) {}
-
-  @override
-  Stream<T> get value => _controller.stream;
-
-  @override
-  List<T> get recordedValue => _data;
-
-  @override
-  Future<void> get complete => _completer.future.catchError((dynamic _) {});
-}
diff --git a/packages/file/lib/src/common.dart b/packages/file/lib/src/common.dart
index 95eb1e1..ea415a2 100644
--- a/packages/file/lib/src/common.dart
+++ b/packages/file/lib/src/common.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'interface.dart';
 
 /// Returns a 'No such file or directory' [FileSystemException].
diff --git a/packages/file/lib/src/forwarding.dart b/packages/file/lib/src/forwarding.dart
index e413acf..82651aa 100644
--- a/packages/file/lib/src/forwarding.dart
+++ b/packages/file/lib/src/forwarding.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 export 'forwarding/forwarding_directory.dart';
 export 'forwarding/forwarding_file.dart';
 export 'forwarding/forwarding_file_system.dart';
diff --git a/packages/file/lib/src/forwarding/forwarding_directory.dart b/packages/file/lib/src/forwarding/forwarding_directory.dart
index 062e02b..099152f 100644
--- a/packages/file/lib/src/forwarding/forwarding_directory.dart
+++ b/packages/file/lib/src/forwarding/forwarding_directory.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/src/io.dart' as io;
@@ -22,11 +23,11 @@
       delegate.createSync(recursive: recursive);
 
   @override
-  Future<Directory> createTemp([String prefix]) async =>
+  Future<Directory> createTemp([String? prefix]) async =>
       wrap(await delegate.createTemp(prefix));
 
   @override
-  Directory createTempSync([String prefix]) =>
+  Directory createTempSync([String? prefix]) =>
       wrap(delegate.createTempSync(prefix));
 
   @override
diff --git a/packages/file/lib/src/forwarding/forwarding_file.dart b/packages/file/lib/src/forwarding/forwarding_file.dart
index 8f98b50..0cbfd3c 100644
--- a/packages/file/lib/src/forwarding/forwarding_file.dart
+++ b/packages/file/lib/src/forwarding/forwarding_file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 import 'dart:convert';
 import 'dart:typed_data';
@@ -72,7 +73,7 @@
       delegate.openSync(mode: mode);
 
   @override
-  Stream<Uint8List> openRead([int start, int end]) => delegate
+  Stream<Uint8List> openRead([int? start, int? end]) => delegate
       .openRead(start, end)
       .cast<List<int>>()
       .transform(const _ToUint8List());
diff --git a/packages/file/lib/src/forwarding/forwarding_file_system.dart b/packages/file/lib/src/forwarding/forwarding_file_system.dart
index 6d027cf..98fda92 100644
--- a/packages/file/lib/src/forwarding/forwarding_file_system.dart
+++ b/packages/file/lib/src/forwarding/forwarding_file_system.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/src/io.dart' as io;
diff --git a/packages/file/lib/src/forwarding/forwarding_file_system_entity.dart b/packages/file/lib/src/forwarding/forwarding_file_system_entity.dart
index 75804a9..7b334b2 100644
--- a/packages/file/lib/src/forwarding/forwarding_file_system_entity.dart
+++ b/packages/file/lib/src/forwarding/forwarding_file_system_entity.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/src/io.dart' as io;
diff --git a/packages/file/lib/src/forwarding/forwarding_link.dart b/packages/file/lib/src/forwarding/forwarding_link.dart
index 6dd0403..6082a65 100644
--- a/packages/file/lib/src/forwarding/forwarding_link.dart
+++ b/packages/file/lib/src/forwarding/forwarding_link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:file/src/io.dart' as io;
diff --git a/packages/file/lib/src/interface.dart b/packages/file/lib/src/interface.dart
index 4662e35..e276fd0 100644
--- a/packages/file/lib/src/interface.dart
+++ b/packages/file/lib/src/interface.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 library file.src.interface;
 
 export 'interface/directory.dart';
diff --git a/packages/file/lib/src/interface/directory.dart b/packages/file/lib/src/interface/directory.dart
index aa736cb..f499371 100644
--- a/packages/file/lib/src/interface/directory.dart
+++ b/packages/file/lib/src/interface/directory.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import '../io.dart' as io;
@@ -17,10 +18,10 @@
   Future<Directory> create({bool recursive = false});
 
   @override
-  Future<Directory> createTemp([String prefix]);
+  Future<Directory> createTemp([String? prefix]);
 
   @override
-  Directory createTempSync([String prefix]);
+  Directory createTempSync([String? prefix]);
 
   @override
   Future<Directory> rename(String newPath);
diff --git a/packages/file/lib/src/interface/error_codes.dart b/packages/file/lib/src/interface/error_codes.dart
index 4983445..e3e0327 100644
--- a/packages/file/lib/src/interface/error_codes.dart
+++ b/packages/file/lib/src/interface/error_codes.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'error_codes_internal.dart'
     if (dart.library.io) 'error_codes_dart_io.dart';
 
@@ -168,7 +169,7 @@
   static int get EXDEV => _platform((_Codes codes) => codes.exdev);
 
   static int _platform(int getCode(_Codes codes)) {
-    _Codes codes = _platforms[operatingSystem] ?? _platforms['linux'];
+    _Codes codes = (_platforms[operatingSystem] ?? _platforms['linux'])!;
     return getCode(codes);
   }
 }
diff --git a/packages/file/lib/src/interface/error_codes_dart_io.dart b/packages/file/lib/src/interface/error_codes_dart_io.dart
index 3f0a97f..da3e4b5 100644
--- a/packages/file/lib/src/interface/error_codes_dart_io.dart
+++ b/packages/file/lib/src/interface/error_codes_dart_io.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:io' show Platform;
 
 /// If we have `dart:io` available, we pull the current operating system from
diff --git a/packages/file/lib/src/interface/error_codes_internal.dart b/packages/file/lib/src/interface/error_codes_internal.dart
index 0a9d7dc..6082bb0 100644
--- a/packages/file/lib/src/interface/error_codes_internal.dart
+++ b/packages/file/lib/src/interface/error_codes_internal.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// In environments that don't have `dart:io`, we can't access the Platform
 /// class to determine what platform we're on, so we just pretend we're on
 /// Linux, meaning we'll get errno values that match Linux's errno.h.
diff --git a/packages/file/lib/src/interface/file.dart b/packages/file/lib/src/interface/file.dart
index ad50475..3025d56 100644
--- a/packages/file/lib/src/interface/file.dart
+++ b/packages/file/lib/src/interface/file.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 import 'dart:convert';
 
diff --git a/packages/file/lib/src/interface/file_system.dart b/packages/file/lib/src/interface/file_system.dart
index b0cc9fd..2198cef 100644
--- a/packages/file/lib/src/interface/file_system.dart
+++ b/packages/file/lib/src/interface/file_system.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import 'package:meta/meta.dart';
diff --git a/packages/file/lib/src/interface/file_system_entity.dart b/packages/file/lib/src/interface/file_system_entity.dart
index 71cb667..b8d1f99 100644
--- a/packages/file/lib/src/interface/file_system_entity.dart
+++ b/packages/file/lib/src/interface/file_system_entity.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import '../io.dart' as io;
diff --git a/packages/file/lib/src/interface/link.dart b/packages/file/lib/src/interface/link.dart
index 433b560..ad1515f 100644
--- a/packages/file/lib/src/interface/link.dart
+++ b/packages/file/lib/src/interface/link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
 import 'dart:async';
 
 import '../io.dart' as io;
diff --git a/packages/file/lib/src/io.dart b/packages/file/lib/src/io.dart
index 9d57e78..7bc7d09 100644
--- a/packages/file/lib/src/io.dart
+++ b/packages/file/lib/src/io.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart=2.10
+
 /// For internal use only!
 ///
 /// This exposes the subset of the `dart:io` interfaces that are required by
diff --git a/packages/file/pubspec.yaml b/packages/file/pubspec.yaml
index 9b065eb..31d7757 100644
--- a/packages/file/pubspec.yaml
+++ b/packages/file/pubspec.yaml
@@ -1,24 +1,18 @@
 name: file
-version: 5.2.2-dev
-authors:
-- Matan Lurey <matanl@google.com>
-- Yegor Jbanov <yjbanov@google.com>
-- Todd Volkert <tvolkert@google.com>
-
+version: 6.0.0-nullsafety
 description:
   A pluggable, mockable file system abstraction for Dart. Supports local file
   system access, as well as in-memory file systems, record-replay file systems,
   and chroot file systems.
-
 homepage: https://github.com/google/file.dart
 
+environment:
+  sdk: '>=2.9.0 <3.0.0'
+
 dependencies:
-  meta: ^1.1.2
-  path: ^1.5.1
+  meta: ^1.3.0-nullsafety.2
+  path: ^1.8.0-nullsafety
 
 dev_dependencies:
   test: '>=1.0.0 <2.0.0'
   file_testing: '>=2.0.0 <3.0.0'
-
-environment:
-  sdk: '>=2.2.2 <3.0.0'
diff --git a/packages/file/test/record_replay_matchers.dart b/packages/file/test/record_replay_matchers.dart
deleted file mode 100644
index 6187242..0000000
--- a/packages/file/test/record_replay_matchers.dart
+++ /dev/null
@@ -1,582 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:file/record_replay.dart';
-import 'package:file/src/backends/record_replay/common.dart'
-    show getSymbolName; // ignore: implementation_imports
-import 'package:test/test.dart';
-
-const Map<Type, String> _kTypeDescriptions = <Type, String>{
-  MethodEvent: 'a method invocation',
-  PropertyGetEvent: 'a property retrieval',
-  PropertySetEvent: 'a property mutation',
-};
-
-const Map<Type, Matcher> _kTypeMatchers = <Type, Matcher>{
-  MethodEvent: TypeMatcher<MethodEvent<dynamic>>(),
-  PropertyGetEvent: TypeMatcher<PropertyGetEvent<dynamic>>(),
-  PropertySetEvent: TypeMatcher<PropertySetEvent<dynamic>>(),
-};
-
-/// Returns a matcher that will match against a [MethodEvent].
-///
-/// If [name] is specified, only method invocations of a matching method name
-/// will successfully match. [name] may be a String, a predicate function,
-/// or a [Matcher].
-///
-/// The returned [MethodInvocation] matcher can be used to further limit the
-/// scope of the match (e.g. by invocation result, target object, etc).
-MethodInvocation invokesMethod([dynamic name]) => MethodInvocation._(name);
-
-/// Returns a matcher that will match against a [PropertyGetEvent].
-///
-/// If [name] is specified, only property retrievals of a matching property name
-/// will successfully match. [name] may be a String, a predicate function,
-/// or a [Matcher].
-///
-/// The returned [PropertyGet] matcher can be used to further limit the
-/// scope of the match (e.g. by property value, target object, etc).
-PropertyGet getsProperty([dynamic name]) => PropertyGet._(name);
-
-/// Returns a matcher that will match against a [PropertySetEvent].
-///
-/// If [name] is specified, only property mutations of a matching property name
-/// will successfully match. [name] may be a String, a predicate function,
-/// or a [Matcher].
-///
-/// The returned [PropertySet] matcher can be used to further limit the
-/// scope of the match (e.g. by property value, target object, etc).
-PropertySet setsProperty([dynamic name]) => PropertySet._(name);
-
-/// A matcher that successfully matches against a future or function
-/// that throws a [NoMatchingInvocationError].
-Matcher throwsNoMatchingInvocationError =
-    throwsA(const TypeMatcher<NoMatchingInvocationError>());
-
-/// Base class for matchers that match against generic [InvocationEvent]
-/// instances.
-abstract class RecordedInvocation<T extends RecordedInvocation<T>>
-    extends Matcher {
-  RecordedInvocation._(Type type) : _typeMatcher = _Type(type);
-
-  final _Type _typeMatcher;
-  final List<Matcher> _fieldMatchers = <Matcher>[];
-
-  /// Limits the scope of the match to invocations that occurred on the
-  /// specified target [object].
-  ///
-  /// [object] may be an instance or a [Matcher]. If it is an instance, it will
-  /// be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  T on(dynamic object) {
-    _fieldMatchers.add(_Target(object));
-    return this as T;
-  }
-
-  /// Limits the scope of the match to invocations that produced the specified
-  /// [result].
-  ///
-  /// For method invocations, this matches against the return value of the
-  /// method. For property retrievals, this matches against the value of the
-  /// property. Property mutations will always produce a `null` result, so
-  /// [PropertySet] will automatically call `withResult(null)` when it is
-  /// instantiated.
-  ///
-  /// [result] may be an instance or a [Matcher]. If it is an instance, it will
-  /// be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  T withResult(dynamic result) {
-    _fieldMatchers.add(_Result(result));
-    return this as T;
-  }
-
-  /// Limits the scope of the match to invocations that were recorded with the
-  /// specified [timestamp].
-  ///
-  /// [timestamp] may be an `int` or a [Matcher]. If it is an `int`, it will
-  /// be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  T withTimestamp(dynamic timestamp) {
-    _fieldMatchers.add(_Timestamp(timestamp));
-    return this as T;
-  }
-
-  /// @nodoc
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
-    if (!_typeMatcher.matches(item, matchState)) {
-      addStateInfo(matchState, <String, Matcher>{'matcher': _typeMatcher});
-      return false;
-    }
-    for (Matcher matcher in _fieldMatchers) {
-      if (!matcher.matches(item, matchState)) {
-        addStateInfo(matchState, <String, Matcher>{'matcher': matcher});
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /// @nodoc
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    Matcher matcher = matchState['matcher'] as Matcher;
-    matcher.describeMismatch(item, description,
-        matchState['state'] as Map<String, dynamic>, verbose);
-    return description;
-  }
-
-  /// @nodoc
-  @override
-  Description describe(Description description) {
-    String divider = '\n  - ';
-    return _typeMatcher
-        .describe(description)
-        .add(':')
-        .addAll(divider, divider, '', _fieldMatchers);
-  }
-}
-
-/// Matchers that matches against [MethodEvent] instances.
-///
-/// Instances of this matcher are obtained by calling [invokesMethod]. Once
-/// instantiated, callers may use this matcher to further qualify the scope
-/// of their match.
-class MethodInvocation extends RecordedInvocation<MethodInvocation> {
-  MethodInvocation._(dynamic methodName) : super._(MethodEvent) {
-    if (methodName != null) {
-      _fieldMatchers.add(_MethodName(methodName));
-    }
-  }
-
-  /// Limits the scope of the match to method invocations that passed the
-  /// specified positional [arguments].
-  ///
-  /// [arguments] may be a list instance or a [Matcher]. If it is a list, it
-  /// will be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  MethodInvocation withPositionalArguments(dynamic arguments) {
-    _fieldMatchers.add(_PositionalArguments(arguments));
-    return this;
-  }
-
-  /// Limits the scope of the match to method invocations that passed the
-  /// specified named argument.
-  ///
-  /// The argument [value] may be an instance or a [Matcher]. If it is an
-  /// instance, it will be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  MethodInvocation withNamedArgument(String name, dynamic value) {
-    _fieldMatchers.add(_NamedArgument(name, value));
-    return this;
-  }
-
-  /// Limits the scope of the match to method invocations that specified no
-  /// named arguments.
-  ///
-  /// Returns this matcher for chaining.
-  MethodInvocation withNoNamedArguments() {
-    _fieldMatchers.add(const _NoNamedArguments());
-    return this;
-  }
-}
-
-/// Matchers that matches against [PropertyGetEvent] instances.
-///
-/// Instances of this matcher are obtained by calling [getsProperty]. Once
-/// instantiated, callers may use this matcher to further qualify the scope
-/// of their match.
-class PropertyGet extends RecordedInvocation<PropertyGet> {
-  PropertyGet._(dynamic propertyName) : super._(PropertyGetEvent) {
-    if (propertyName != null) {
-      _fieldMatchers.add(_GetPropertyName(propertyName));
-    }
-  }
-}
-
-/// Matchers that matches against [PropertySetEvent] instances.
-///
-/// Instances of this matcher are obtained by calling [setsProperty]. Once
-/// instantiated, callers may use this matcher to further qualify the scope
-/// of their match.
-class PropertySet extends RecordedInvocation<PropertySet> {
-  PropertySet._(dynamic propertyName) : super._(PropertySetEvent) {
-    withResult(null);
-    if (propertyName != null) {
-      _fieldMatchers.add(_SetPropertyName(propertyName));
-    }
-  }
-
-  /// Limits the scope of the match to property mutations that set the property
-  /// to the specified [value].
-  ///
-  /// [value] may be an instance or a [Matcher]. If it is an instance, it will
-  /// be automatically wrapped in an equality matcher.
-  ///
-  /// Returns this matcher for chaining.
-  PropertySet toValue(dynamic value) {
-    _fieldMatchers.add(_SetValue(value));
-    return this;
-  }
-}
-
-class _Target extends Matcher {
-  _Target(dynamic target) : _matcher = wrapMatcher(target);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.object, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    description.add('was invoked on: ${item.object}');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(item.object, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description desc) {
-    desc.add('on object: ');
-    return _matcher.describe(desc);
-  }
-}
-
-class _Result extends Matcher {
-  _Result(dynamic result) : _matcher = wrapMatcher(result);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.result, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    description.add('returned: ${item.result}');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(item.result, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description desc) {
-    desc.add('with result: ');
-    return _matcher.describe(desc);
-  }
-}
-
-class _Timestamp extends Matcher {
-  _Timestamp(dynamic timestamp) : _matcher = wrapMatcher(timestamp);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.timestamp, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    description.add('has timestamp: ${item.timestamp}');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(item.timestamp, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description desc) {
-    desc.add('with timestamp: ');
-    return _matcher.describe(desc);
-  }
-}
-
-class _Type extends Matcher {
-  const _Type(this.type);
-
-  final Type type;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _kTypeMatchers[type].matches(item, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    Type type;
-    for (Type matchType in _kTypeMatchers.keys) {
-      Matcher matcher = _kTypeMatchers[matchType];
-      if (matcher.matches(item, <dynamic, dynamic>{})) {
-        type = matchType;
-        break;
-      }
-    }
-    if (type != null) {
-      description.add('is ').add(_kTypeDescriptions[type]);
-    } else {
-      description.add('is a ${item.runtimeType}');
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description desc) => desc.add(_kTypeDescriptions[type]);
-}
-
-class _MethodName extends Matcher {
-  _MethodName(dynamic name) : _matcher = wrapMatcher(name);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(getSymbolName(item.method as Symbol), matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    String methodName = getSymbolName(item.method as Symbol);
-    description.add('invoked method: \'$methodName\'');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(methodName, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description desc) {
-    desc.add('method: ');
-    return _matcher.describe(desc);
-  }
-}
-
-class _PositionalArguments extends Matcher {
-  _PositionalArguments(dynamic value) : _matcher = wrapMatcher(value);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.positionalArguments, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    return _matcher.describeMismatch(
-        item.positionalArguments, description, matchState, verbose);
-  }
-
-  @override
-  Description describe(Description desc) {
-    desc.add('with positional arguments: ');
-    return _matcher.describe(desc);
-  }
-}
-
-class _NamedArgument extends Matcher {
-  _NamedArgument(this.name, this.value)
-      : _matcher = containsPair(Symbol(name), value);
-
-  final String name;
-  final dynamic value;
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.namedArguments, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    return _matcher.describeMismatch(
-        item.namedArguments, description, matchState, verbose);
-  }
-
-  @override
-  Description describe(Description description) =>
-      description.add('with named argument "$name" = $value');
-}
-
-class _NoNamedArguments extends Matcher {
-  const _NoNamedArguments();
-
-  Matcher get _matcher => isEmpty;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.namedArguments, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    return _matcher.describeMismatch(
-        item.namedArguments, description, matchState, verbose);
-  }
-
-  @override
-  Description describe(Description description) =>
-      description.add('with no named arguments');
-}
-
-class _GetPropertyName extends Matcher {
-  _GetPropertyName(dynamic _name) : _matcher = wrapMatcher(_name);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(getSymbolName(item.property as Symbol), matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    String propertyName = getSymbolName(item.property as Symbol);
-    description.add('got property: \'$propertyName\'');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(propertyName, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description description) {
-    description.add('gets property: ');
-    return _matcher.describe(description);
-  }
-}
-
-class _SetPropertyName extends Matcher {
-  _SetPropertyName(dynamic _name) : _matcher = wrapMatcher(_name);
-
-  final Matcher _matcher;
-
-  /// Strips the trailing `=` off the symbol name to get the property name.
-  String _getPropertyName(dynamic item) {
-    String symbolName = getSymbolName(item.property as Symbol);
-    return symbolName.substring(0, symbolName.length - 1);
-  }
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) {
-    return _matcher.matches(_getPropertyName(item), matchState);
-  }
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    String propertyName = _getPropertyName(item);
-    description.add('set property: \'$propertyName\'');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(propertyName, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description description) {
-    description.add('of property: ');
-    return _matcher.describe(description);
-  }
-}
-
-class _SetValue extends Matcher {
-  _SetValue(dynamic value) : _matcher = wrapMatcher(value);
-
-  final Matcher _matcher;
-
-  @override
-  bool matches(dynamic item, Map<dynamic, dynamic> matchState) =>
-      _matcher.matches(item.value, matchState);
-
-  @override
-  Description describeMismatch(
-    dynamic item,
-    Description description,
-    Map<dynamic, dynamic> matchState,
-    bool verbose,
-  ) {
-    description.add('set value: ${item.value}');
-    Description matcherDesc = StringDescription();
-    _matcher.describeMismatch(item.value, matcherDesc, matchState, verbose);
-    if (matcherDesc.length > 0) {
-      description.add('\n   Which: ').add(matcherDesc.toString());
-    }
-    return description;
-  }
-
-  @override
-  Description describe(Description description) {
-    description.add('to value: ');
-    return _matcher.describe(description);
-  }
-}
diff --git a/packages/file/test/recording_test.dart b/packages/file/test/recording_test.dart
deleted file mode 100644
index 968dad1..0000000
--- a/packages/file/test/recording_test.dart
+++ /dev/null
@@ -1,944 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:file/file.dart';
-import 'package:file/memory.dart';
-import 'package:file/record_replay.dart';
-import 'package:file/src/backends/record_replay/codecs.dart';
-import 'package:file/src/backends/record_replay/common.dart' hide TypeMatcher;
-import 'package:file/src/backends/record_replay/events.dart';
-import 'package:file/src/backends/record_replay/mutable_recording.dart';
-import 'package:file/src/backends/record_replay/recording_proxy_mixin.dart';
-import 'package:file_testing/file_testing.dart';
-import 'package:path/path.dart' as p;
-import 'package:test/test.dart';
-
-import 'common_tests.dart';
-import 'record_replay_matchers.dart';
-
-void main() {
-  group('SupportingCode', () {
-    _BasicClass delegate;
-    _RecordingClass rc;
-    MutableRecording recording;
-
-    setUp(() {
-      delegate = _BasicClass();
-      rc = _RecordingClass(
-        delegate: delegate,
-        stopwatch: _FakeStopwatch(10),
-        destination: MemoryFileSystem().directory('/tmp')..createSync(),
-      );
-      recording = rc.recording;
-    });
-
-    group('InvocationEvent', () {
-      test('recordsAllPropertyGetMetadata', () {
-        delegate.basicProperty = 'foo';
-        String value = rc.basicProperty;
-        expect(recording.events, hasLength(1));
-        expect(
-            recording.events[0],
-            getsProperty('basicProperty')
-                .on(rc)
-                .withResult(value)
-                .withTimestamp(10));
-      });
-
-      test('recordsAllPropertySetMetadata', () {
-        rc.basicProperty = 'foo';
-        expect(recording.events, hasLength(1));
-        expect(
-            recording.events[0],
-            setsProperty('basicProperty')
-                .on(rc)
-                .toValue('foo')
-                .withTimestamp(10));
-      });
-
-      test('recordsAllMethodInvocationMetadata', () {
-        String result = rc.basicMethod('foo', namedArg: 'bar');
-        expect(recording.events, hasLength(1));
-        expect(
-            recording.events[0],
-            invokesMethod('basicMethod')
-                .on(rc)
-                .withPositionalArguments(<String>['foo'])
-                .withNamedArgument('namedArg', 'bar')
-                .withResult(result)
-                .withTimestamp(10));
-      });
-
-      test('resultIncompleteUntilFutureCompletes', () async {
-        delegate.basicProperty = 'foo';
-        rc.futureProperty; // ignore: unawaited_futures
-        expect(recording.events, hasLength(1));
-        expect(
-            recording.events[0],
-            getsProperty('futureProperty')
-                .on(rc)
-                .withResult(isNull)
-                .withTimestamp(10));
-        await recording.events[0].done;
-        expect(
-            recording.events[0],
-            getsProperty('futureProperty')
-                .on(rc)
-                .withResult('future.foo')
-                .withTimestamp(10));
-      });
-
-      test('resultIncompleteUntilStreamCompletes', () async {
-        Stream<String> stream = rc.streamMethod('foo', namedArg: 'bar');
-        stream.listen((_) {});
-        expect(recording.events, hasLength(1));
-        expect(
-            recording.events[0],
-            invokesMethod('streamMethod')
-                .on(rc)
-                .withPositionalArguments(<String>['foo'])
-                .withNamedArgument('namedArg', 'bar')
-                .withResult(allOf(isList, isEmpty))
-                .withTimestamp(10));
-        await recording.events[0].done;
-        expect(
-            recording.events[0],
-            invokesMethod('streamMethod')
-                .on(rc)
-                .withPositionalArguments(<String>['foo'])
-                .withNamedArgument('namedArg', 'bar')
-                .withResult(<String>['stream', 'foo', 'bar'])
-                .withTimestamp(10));
-      });
-    });
-
-    group('MutableRecording', () {
-      group('flush', () {
-        test('writesManifestToFileSystemAsJson', () async {
-          rc.basicProperty = 'foo';
-          String value = rc.basicProperty;
-          rc.basicMethod(value, namedArg: 'bar');
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(3));
-          expect(manifest[0], <String, dynamic>{
-            'type': 'set',
-            'property': 'basicProperty=',
-            'value': 'foo',
-            'object': '_RecordingClass',
-            'result': null,
-            'error': null,
-            'timestamp': 10,
-          });
-          expect(manifest[1], <String, dynamic>{
-            'type': 'get',
-            'property': 'basicProperty',
-            'object': '_RecordingClass',
-            'result': 'foo',
-            'error': null,
-            'timestamp': 11,
-          });
-          expect(manifest[2], <String, dynamic>{
-            'type': 'invoke',
-            'method': 'basicMethod',
-            'positionalArguments': <String>['foo'],
-            'namedArguments': <String, dynamic>{'namedArg': 'bar'},
-            'object': '_RecordingClass',
-            'result': 'foo.bar',
-            'error': null,
-            'timestamp': 12
-          });
-        });
-
-        test('awaitsPendingResultsIndefinitelyByDefault', () async {
-          rc.veryLongFutureMethod(); // ignore: unawaited_futures
-          expect(recording.flush().timeout(const Duration(milliseconds: 50)),
-              throwsA(const TypeMatcher<TimeoutException>()));
-        });
-
-        test('succeedsIfAwaitPendingResultsThatComplete', () async {
-          rc.futureMethod('foo', namedArg: 'bar'); // ignore: unawaited_futures
-          await recording.flush(
-              pendingResultTimeout: const Duration(seconds: 30));
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest[0], containsPair('result', 'future.foo.bar'));
-        });
-
-        test('succeedsIfAwaitPendingResultsThatTimeout', () async {
-          rc.veryLongFutureMethod(); // ignore: unawaited_futures
-          DateTime before = DateTime.now();
-          await recording.flush(
-              pendingResultTimeout: const Duration(milliseconds: 250));
-          DateTime after = DateTime.now();
-          Duration delta = after.difference(before);
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest[0], containsPair('result', isNull));
-          expect(delta.inMilliseconds, greaterThanOrEqualTo(250));
-        });
-
-        test('throwsIfAlreadyFlushing', () {
-          rc.basicProperty = 'foo';
-          recording.flush();
-          expect(recording.flush(), throwsA(isStateError));
-        });
-      });
-    });
-
-    group('encode', () {
-      test('performsDeepEncoding', () async {
-        rc.basicProperty = 'foo';
-        rc.basicProperty; // ignore: unnecessary_statements
-        rc.basicMethod('bar', namedArg: 'baz');
-        await rc.futureProperty;
-        await rc.futureMethod('qux', namedArg: 'quz');
-        await rc.streamMethod('quux', namedArg: 'quuz').drain<void>();
-        List<Map<String, dynamic>> manifest =
-            (await encode(recording.events) as List<dynamic>)
-                .cast<Map<String, dynamic>>();
-        expect(manifest[0], <String, dynamic>{
-          'type': 'set',
-          'property': 'basicProperty=',
-          'value': 'foo',
-          'object': '_RecordingClass',
-          'result': isNull,
-          'error': null,
-          'timestamp': 10,
-        });
-        expect(manifest[1], <String, dynamic>{
-          'type': 'get',
-          'property': 'basicProperty',
-          'object': '_RecordingClass',
-          'result': 'foo',
-          'error': null,
-          'timestamp': 11,
-        });
-        expect(manifest[2], <String, dynamic>{
-          'type': 'invoke',
-          'method': 'basicMethod',
-          'positionalArguments': <String>['bar'],
-          'namedArguments': <String, String>{'namedArg': 'baz'},
-          'object': '_RecordingClass',
-          'result': 'bar.baz',
-          'error': null,
-          'timestamp': 12,
-        });
-        expect(manifest[3], <String, dynamic>{
-          'type': 'get',
-          'property': 'futureProperty',
-          'object': '_RecordingClass',
-          'result': 'future.foo',
-          'error': null,
-          'timestamp': 13,
-        });
-        expect(manifest[4], <String, dynamic>{
-          'type': 'invoke',
-          'method': 'futureMethod',
-          'positionalArguments': <String>['qux'],
-          'namedArguments': <String, String>{'namedArg': 'quz'},
-          'object': '_RecordingClass',
-          'result': 'future.qux.quz',
-          'error': null,
-          'timestamp': 14,
-        });
-        expect(manifest[5], <String, dynamic>{
-          'type': 'invoke',
-          'method': 'streamMethod',
-          'positionalArguments': <String>['quux'],
-          'namedArguments': <String, String>{'namedArg': 'quuz'},
-          'object': '_RecordingClass',
-          'result': <String>['stream', 'quux', 'quuz'],
-          'error': null,
-          'timestamp': 15,
-        });
-      });
-    });
-
-    group('deeplyEqual', () {
-      Map<String, dynamic> newMap({
-        String stringValue = 'foo',
-        bool boolValue = true,
-        String lastListValue = 'c',
-        int lastMapValue = 2,
-      }) {
-        return <String, dynamic>{
-          'string': stringValue,
-          'bool': boolValue,
-          'list': <String>['a', 'b', lastListValue],
-          'map': <Symbol, int>{
-            #foo: 1,
-            #bar: lastMapValue,
-          },
-        };
-      }
-
-      test('primitives', () {
-        expect(deeplyEqual(1, 1), isTrue);
-        expect(deeplyEqual(1, 2), isFalse);
-        expect(deeplyEqual('1', '1'), isTrue);
-        expect(deeplyEqual('1', '2'), isFalse);
-        expect(deeplyEqual(true, true), isTrue);
-        expect(deeplyEqual(true, false), isFalse);
-        expect(deeplyEqual(null, null), isTrue);
-        expect(deeplyEqual(1, '1'), isFalse);
-      });
-
-      test('listOfPrimitives', () {
-        expect(deeplyEqual(<int>[], <int>[]), isTrue);
-        expect(deeplyEqual(<int>[1, 2, 3], <int>[1, 2, 3]), isTrue);
-        expect(deeplyEqual(<int>[1, 2, 3], <int>[1, 3, 2]), isFalse);
-        expect(deeplyEqual(<int>[1, 2, 3], <int>[1, 2]), isFalse);
-        expect(deeplyEqual(<int>[1, 2, 3], <int>[1, 2, 3, 4]), isFalse);
-        expect(deeplyEqual(<String>['a', 'b'], <String>['a', 'b']), isTrue);
-        expect(deeplyEqual(<String>['a', 'b'], <String>['b', 'a']), isFalse);
-        expect(deeplyEqual(<String>['a', 'b'], <String>['a']), isFalse);
-        expect(deeplyEqual(<int>[], <dynamic>[]), isFalse);
-        expect(deeplyEqual(<int>[], null), isFalse);
-      });
-
-      test('mapOfPrimitives', () {
-        expect(deeplyEqual(<String, int>{}, <String, int>{}), isTrue);
-        expect(deeplyEqual(<int, int>{1: 2}, <int, int>{1: 2}), isTrue);
-        expect(deeplyEqual(<int, int>{1: 2}, <int, int>{1: 3}), isFalse);
-        expect(deeplyEqual(<int, int>{1: 2}, <int, int>{}), isFalse);
-        expect(deeplyEqual(<int, int>{}, <int, int>{1: 2}), isFalse);
-        expect(deeplyEqual(<String, int>{}, <int, int>{}), isFalse);
-        expect(deeplyEqual(<String, int>{}, <dynamic, dynamic>{}), isFalse);
-        expect(deeplyEqual(<String, int>{}, null), isFalse);
-      });
-
-      test('listOfMaps', () {
-        expect(deeplyEqual(newMap(), newMap()), isTrue);
-        expect(deeplyEqual(newMap(), newMap(stringValue: 'bar')), isFalse);
-        expect(deeplyEqual(newMap(), newMap(boolValue: false)), isFalse);
-        expect(deeplyEqual(newMap(), newMap(lastListValue: 'd')), isFalse);
-        expect(deeplyEqual(newMap(), newMap(lastMapValue: 3)), isFalse);
-      });
-    });
-  });
-
-  group('RecordingFileSystem', () {
-    RecordingFileSystem fs;
-    MemoryFileSystem delegate;
-    LiveRecording recording;
-
-    setUp(() {
-      delegate = MemoryFileSystem();
-      fs = RecordingFileSystem(
-        delegate: delegate,
-        destination: MemoryFileSystem().directory('/tmp')..createSync(),
-      );
-      recording = fs.recording;
-    });
-
-    runCommonTests(() => fs);
-
-    group('recording', () {
-      test('supportsMultipleActions', () {
-        fs.directory('/foo').createSync();
-        fs.file('/foo/bar').writeAsStringSync('BAR');
-        List<InvocationEvent<dynamic>> events = recording.events;
-        expect(events, hasLength(4));
-        expect(events[0], invokesMethod('directory'));
-        expect(events[1], invokesMethod('createSync'));
-        expect(events[2], invokesMethod('file'));
-        expect(events[3], invokesMethod('writeAsStringSync'));
-        expect(events[0].result, events[1].object);
-        expect(events[2].result, events[3].object);
-      });
-
-      group('FileSystem', () {
-        test('directory', () {
-          fs.directory('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            invokesMethod('directory').on(fs).withPositionalArguments(
-                <String>['/foo']).withResult(isDirectory),
-          );
-        });
-
-        test('file', () {
-          fs.file('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            invokesMethod('file')
-                .on(fs)
-                .withPositionalArguments(<String>['/foo']).withResult(isFile),
-          );
-        });
-
-        test('link', () {
-          fs.link('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            invokesMethod('link')
-                .on(fs)
-                .withPositionalArguments(<String>['/foo']).withResult(isLink),
-          );
-        });
-
-        test('path', () {
-          fs.path;
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            getsProperty('path')
-                .on(fs)
-                .withResult(const TypeMatcher<p.Context>()),
-          );
-        });
-
-        test('systemTempDirectory', () {
-          fs.systemTempDirectory;
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-              events[0],
-              getsProperty('systemTempDirectory')
-                  .on(fs)
-                  .withResult(isDirectory));
-        });
-
-        group('currentDirectory', () {
-          test('get', () {
-            fs.currentDirectory;
-            List<InvocationEvent<dynamic>> events = recording.events;
-            expect(events, hasLength(1));
-            expect(
-                events[0],
-                getsProperty('currentDirectory')
-                    .on(fs)
-                    .withResult(isDirectory));
-          });
-
-          test('setToString', () {
-            delegate.directory('/foo').createSync();
-            fs.currentDirectory = '/foo';
-            List<InvocationEvent<dynamic>> events = recording.events;
-            expect(events, hasLength(1));
-            expect(events[0],
-                setsProperty('currentDirectory').on(fs).toValue('/foo'));
-          });
-
-          test('setToRecordingDirectory', () {
-            delegate.directory('/foo').createSync();
-            fs.currentDirectory = fs.directory('/foo');
-            List<InvocationEvent<dynamic>> events = recording.events;
-            expect(events.length, greaterThanOrEqualTo(2));
-            expect(events[0], invokesMethod().withResult(isDirectory));
-            Directory directory = events[0].result as Directory;
-            expect(
-                events,
-                contains(setsProperty('currentDirectory')
-                    .on(fs)
-                    .toValue(directory)));
-          });
-
-          test('setToNonRecordingDirectory', () {
-            Directory dir = delegate.directory('/foo');
-            dir.createSync();
-            fs.currentDirectory = dir;
-            List<InvocationEvent<dynamic>> events = recording.events;
-            expect(events, hasLength(1));
-            expect(events[0],
-                setsProperty('currentDirectory').on(fs).toValue(isDirectory));
-          });
-        });
-
-        test('stat', () async {
-          delegate.file('/foo').createSync();
-          await fs.stat('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            invokesMethod('stat').on(fs).withPositionalArguments(
-                <String>['/foo']).withResult(isFileStat),
-          );
-        });
-
-        test('statSync', () {
-          delegate.file('/foo').createSync();
-          fs.statSync('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-            events[0],
-            invokesMethod('statSync').on(fs).withPositionalArguments(
-                <String>['/foo']).withResult(isFileStat),
-          );
-        });
-
-        test('identical', () async {
-          delegate.file('/foo').createSync();
-          delegate.file('/bar').createSync();
-          await fs.identical('/foo', '/bar');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-              events[0],
-              invokesMethod('identical').on(fs).withPositionalArguments(
-                  <String>['/foo', '/bar']).withResult(isFalse));
-        });
-
-        test('identicalSync', () {
-          delegate.file('/foo').createSync();
-          delegate.file('/bar').createSync();
-          fs.identicalSync('/foo', '/bar');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-              events[0],
-              invokesMethod('identicalSync').on(fs).withPositionalArguments(
-                  <String>['/foo', '/bar']).withResult(isFalse));
-        });
-
-        test('isWatchSupported', () {
-          fs.isWatchSupported;
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(events[0],
-              getsProperty('isWatchSupported').on(fs).withResult(isFalse));
-        });
-
-        test('type', () async {
-          delegate.file('/foo').createSync();
-          await fs.type('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-              events[0],
-              invokesMethod('type').on(fs).withPositionalArguments(
-                  <String>['/foo']).withResult(FileSystemEntityType.file));
-        });
-
-        test('typeSync', () {
-          delegate.file('/foo').createSync();
-          fs.typeSync('/foo');
-          List<InvocationEvent<dynamic>> events = recording.events;
-          expect(events, hasLength(1));
-          expect(
-              events[0],
-              invokesMethod('typeSync').on(fs).withPositionalArguments(
-                  <String>['/foo']).withResult(FileSystemEntityType.file));
-        });
-      });
-
-      group('Directory', () {
-        test('create', () async {
-          await fs.directory('/foo').create();
-          expect(
-              recording.events,
-              contains(invokesMethod('create')
-                  .on(isDirectory)
-                  .withNamedArgument('recursive', false)
-                  .withResult(isDirectory)));
-        });
-
-        test('createSync', () {
-          fs.directory('/foo').createSync();
-          expect(
-              recording.events,
-              contains(invokesMethod('createSync')
-                  .on(isDirectory)
-                  .withNamedArgument('recursive', false)
-                  .withResult(isNull)));
-        });
-
-        test('list', () async {
-          await delegate.directory('/foo').create();
-          await delegate.directory('/bar').create();
-          await delegate.file('/baz').create();
-          Stream<FileSystemEntity> stream = fs.directory('/').list();
-          await stream.drain<void>();
-          expect(
-            recording.events,
-            contains(invokesMethod('list')
-                .on(isDirectory)
-                .withNamedArgument('recursive', false)
-                .withNamedArgument('followLinks', true)
-                .withResult(hasLength(3))),
-          );
-        });
-      });
-
-      group('File', () {
-        // TODO(tvolkert): Fill in these test stubs
-        test('create', () {});
-
-        test('createSync', () {});
-
-        test('rename', () {});
-
-        test('renameSync', () {});
-
-        test('copy', () {});
-
-        test('copySync', () {});
-
-        test('length', () {});
-
-        test('lengthSync', () {});
-
-        test('absolute', () {});
-
-        test('lastModified', () {});
-
-        test('lastModifiedSync', () {});
-
-        test('open', () {});
-
-        test('openSync', () {});
-
-        test('openRead', () async {
-          String content = 'Hello\nWorld';
-          await delegate.file('/foo').writeAsString(content, flush: true);
-          Stream<List<int>> stream = fs.file('/foo').openRead();
-          await stream.drain<void>();
-          expect(
-              recording.events,
-              contains(invokesMethod('openRead')
-                  .on(isFile)
-                  .withPositionalArguments(<int>[null, null])
-                  .withNoNamedArguments()
-                  .withResult(isList)));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'openRead'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', <int>[null, null]),
-                containsPair('namedArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('openWrite', () {});
-
-        test('readAsBytes', () async {
-          String content = 'Hello\nWorld';
-          await delegate.file('/foo').writeAsString(content, flush: true);
-          await fs.file('/foo').readAsBytes();
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsBytes')
-                  .on(isFile)
-                  .withNoNamedArguments()
-                  .withResult(allOf(isList, hasLength(content.length)))));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsBytes'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('namedArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('readAsBytesSync', () async {
-          String content = 'Hello\nWorld';
-          await delegate.file('/foo').writeAsString(content, flush: true);
-          fs.file('/foo').readAsBytesSync();
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsBytesSync')
-                  .on(isFile)
-                  .withNoNamedArguments()
-                  .withResult(allOf(isList, hasLength(content.length)))));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsBytesSync'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('namedArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('readAsString', () async {
-          String content = 'Hello\nWorld';
-          await delegate
-              .file('/foo')
-              .writeAsString(content, encoding: latin1, flush: true);
-          await fs.file('/foo').readAsString(encoding: latin1);
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsString')
-                  .on(isFile)
-                  .withNamedArgument('encoding', latin1)
-                  .withResult(content)));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsString'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-                containsPair(
-                    'namedArguments',
-                    allOf(
-                      hasLength(1),
-                      containsPair('encoding', 'iso-8859-1'),
-                    )),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('readAsStringSync', () async {
-          String content = 'Hello\nWorld';
-          await delegate
-              .file('/foo')
-              .writeAsString(content, encoding: latin1, flush: true);
-          fs.file('/foo').readAsStringSync(encoding: latin1);
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsStringSync')
-                  .on(isFile)
-                  .withNamedArgument('encoding', latin1)
-                  .withResult(content)));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsStringSync'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-                containsPair(
-                    'namedArguments',
-                    allOf(
-                      hasLength(1),
-                      containsPair('encoding', 'iso-8859-1'),
-                    )),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('readAsLines', () async {
-          // [readAsLines] is appropriate only for text files, and POSIX
-          // requires that valid text files end with a terminating newline.
-          String content = 'Hello\nWorld\n';
-          await delegate.file('/foo').writeAsString(content, flush: true);
-          await fs.file('/foo').readAsLines();
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsLines')
-                  .on(isFile)
-                  .withNamedArgument('encoding', utf8)
-                  .withResult(<String>['Hello', 'World'])));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsLines'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-                containsPair(
-                    'namedArguments', <String, String>{'encoding': 'utf-8'}),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('readAsLinesSync', () async {
-          // [readAsLinesSync] is appropriate only for text files, and POSIX
-          // requires that valid text files end with a terminating newline.
-          String content = 'Hello\nWorld\n';
-          await delegate.file('/foo').writeAsString(content, flush: true);
-          fs.file('/foo').readAsLinesSync();
-          expect(
-              recording.events,
-              contains(invokesMethod('readAsLinesSync')
-                  .on(isFile)
-                  .withNamedArgument('encoding', utf8)
-                  .withResult(<String>['Hello', 'World'])));
-          await recording.flush();
-          List<Map<String, dynamic>> manifest = _loadManifest(recording);
-          expect(manifest, hasLength(2));
-          expect(
-              manifest[1],
-              allOf(
-                containsPair('type', 'invoke'),
-                containsPair('method', 'readAsLinesSync'),
-                containsPair('object', matches(r'^RecordingFile@[0-9]+$')),
-                containsPair('positionalArguments', isEmpty),
-                containsPair('result', matches(r'^![0-9]+.foo$')),
-                containsPair(
-                    'namedArguments', <String, String>{'encoding': 'utf-8'}),
-              ));
-          File file =
-              _getRecordingFile(recording, manifest[1]['result'] as String);
-          expect(file, exists);
-          expect(await file.readAsString(), content);
-        });
-
-        test('writeAsBytes', () {});
-
-        test('writeAsBytesSync', () {});
-
-        test('writeAsString', () {});
-
-        test('writeAsStringSync', () {});
-      });
-
-      group('Link', () {});
-    });
-  });
-}
-
-List<Map<String, dynamic>> _loadManifest(LiveRecording recording) {
-  List<FileSystemEntity> files = recording.destination.listSync();
-  File manifestFile = files.singleWhere(
-      (FileSystemEntity entity) => entity.basename == kManifestName) as File;
-  return (const JsonDecoder().convert(manifestFile.readAsStringSync())
-          as List<dynamic>)
-      .cast<Map<String, dynamic>>();
-}
-
-File _getRecordingFile(LiveRecording recording, String manifestReference) {
-  expect(manifestReference, startsWith('!'));
-  String basename = manifestReference.substring(1);
-  String dirname = recording.destination.path;
-  String path = recording.destination.fileSystem.path.join(dirname, basename);
-  return recording.destination.fileSystem.file(path);
-}
-
-class _BasicClass {
-  String basicProperty;
-
-  Future<String> get futureProperty async => 'future.$basicProperty';
-
-  String basicMethod(String positionalArg, {String namedArg}) =>
-      '$positionalArg.$namedArg';
-
-  Future<String> futureMethod(String positionalArg, {String namedArg}) async {
-    await Future<void>.delayed(const Duration(milliseconds: 500));
-    String basicValue = basicMethod(positionalArg, namedArg: namedArg);
-    return 'future.$basicValue';
-  }
-
-  Stream<String> streamMethod(String positionalArg, {String namedArg}) async* {
-    yield 'stream';
-    yield positionalArg;
-    yield namedArg;
-  }
-
-  Future<String> veryLongFutureMethod() async {
-    await Future<void>.delayed(const Duration(seconds: 1));
-    return 'future';
-  }
-
-  Stream<String> infiniteStreamMethod() async* {
-    yield 'stream';
-    int i = 0;
-    while (i >= 0) {
-      yield '${i++}';
-      await Future<void>.delayed(const Duration(seconds: 1));
-    }
-  }
-}
-
-class _RecordingClass extends Object
-    with RecordingProxyMixin
-    implements _BasicClass {
-  _RecordingClass({
-    this.delegate,
-    this.stopwatch,
-    Directory destination,
-  }) : recording = MutableRecording(destination) {
-    methods.addAll(<Symbol, Function>{
-      #basicMethod: delegate.basicMethod,
-      #futureMethod: delegate.futureMethod,
-      #streamMethod: delegate.streamMethod,
-      #veryLongFutureMethod: delegate.veryLongFutureMethod,
-      #infiniteStreamMethod: delegate.infiniteStreamMethod,
-    });
-
-    properties.addAll(<Symbol, Function>{
-      #basicProperty: () => delegate.basicProperty,
-      const Symbol('basicProperty='): (String value) {
-        delegate.basicProperty = value;
-      },
-      #futureProperty: () => delegate.futureProperty,
-    });
-  }
-
-  final _BasicClass delegate;
-
-  @override
-  String get identifier => '$runtimeType';
-
-  @override
-  final MutableRecording recording;
-
-  @override
-  final Stopwatch stopwatch;
-}
-
-class _FakeStopwatch implements Stopwatch {
-  _FakeStopwatch(this._value);
-
-  int _value;
-
-  @override
-  int get elapsedMilliseconds => _value++;
-
-  @override
-  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/packages/file/test/replay_test.dart b/packages/file/test/replay_test.dart
deleted file mode 100644
index 192d161..0000000
--- a/packages/file/test/replay_test.dart
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:file/file.dart';
-import 'package:file/memory.dart';
-import 'package:file/record_replay.dart';
-import 'package:file/src/backends/record_replay/common.dart'
-    show describeInvocation;
-import 'package:file_testing/file_testing.dart';
-import 'package:path/path.dart' as path;
-import 'package:test/test.dart';
-
-import 'common_tests.dart';
-import 'record_replay_matchers.dart';
-
-void main() {
-  group('Replay', () {
-    RecordingFileSystem recordingFileSystem;
-    MemoryFileSystem memoryFileSystem;
-    LiveRecording recording;
-
-    setUp(() {
-      memoryFileSystem = MemoryFileSystem();
-      recordingFileSystem = RecordingFileSystem(
-        delegate: memoryFileSystem,
-        destination: MemoryFileSystem().directory('/tmp')..createSync(),
-      );
-      recording = recordingFileSystem.recording;
-    });
-
-    /// Creates a new [ReplayFileSystem] that will replay a recording of the
-    /// events that have been recorded within [recordingFileSystem] thus far.
-    Future<ReplayFileSystem> replay() async {
-      await recording.flush();
-      return ReplayFileSystem(recording: recording.destination);
-    }
-
-    runCommonTests(
-      () => recordingFileSystem,
-      replay: replay,
-      skip: <String>[
-        // ReplayFileSystem does not yet support futures & streams that throw
-        'File > openRead > throws.*',
-        'File > openWrite > throws.*',
-        'File > openWrite > ioSink > throwsIfAddError',
-        'File > openWrite > ioSink > addStream > blocks.*',
-        'File > openWrite > ioSink > ignoresDataWrittenAfterClose',
-
-        // TODO(jamesderlin): ReplayFileSystem does not yet support functions
-        // that mutate arguments, and error-checking for async functions is not
-        // implemented (https://github.com/google/file.dart/issues/144)
-        'File > open .* RandomAccessFile .* readInto.*',
-        'File > open .* RandomAccessFile .* throwsIfAsyncUnawaited',
-      ],
-    );
-
-    group('ReplayFileSystem', () {
-      test('directory', () async {
-        recordingFileSystem.directory('/foo');
-        ReplayFileSystem fs = await replay();
-        Directory dir = fs.directory('/foo');
-        expect(dir, isDirectory);
-        expect(() => dir.path, throwsNoMatchingInvocationError);
-        expect(() => fs.directory('/foo'), throwsNoMatchingInvocationError);
-      });
-
-      test('file', () async {
-        recordingFileSystem.file('/foo');
-        ReplayFileSystem fs = await replay();
-        expect(fs.file('/foo'), isFile);
-        expect(() => fs.file('/foo'), throwsNoMatchingInvocationError);
-      });
-
-      test('link', () async {
-        recordingFileSystem.link('/foo');
-        ReplayFileSystem fs = await replay();
-        expect(fs.link('/foo'), isLink);
-        expect(() => fs.link('/foo'), throwsNoMatchingInvocationError);
-      });
-
-      test('path', () async {
-        path.Context context = recordingFileSystem.path;
-        ReplayFileSystem fs = await replay();
-        path.Context replayContext = fs.path;
-        expect(() => fs.path, throwsNoMatchingInvocationError);
-        expect(replayContext.style, context.style);
-        expect(replayContext.current, context.current);
-      });
-
-      test('systemTempDirectory', () async {
-        recordingFileSystem.systemTempDirectory;
-        ReplayFileSystem fs = await replay();
-        Directory dir = fs.systemTempDirectory;
-        expect(dir, isDirectory);
-        expect(() => dir.path, throwsNoMatchingInvocationError);
-        expect(() => fs.systemTempDirectory, throwsNoMatchingInvocationError);
-      });
-
-      group('currentDirectory', () {
-        test('get', () async {
-          recordingFileSystem.currentDirectory;
-          ReplayFileSystem fs = await replay();
-          Directory dir = fs.currentDirectory;
-          expect(dir, isDirectory);
-          expect(() => dir.path, throwsNoMatchingInvocationError);
-          expect(() => fs.currentDirectory, throwsNoMatchingInvocationError);
-        });
-
-        test('setToString', () async {
-          memoryFileSystem.directory('/foo').createSync();
-          recordingFileSystem.currentDirectory = '/foo';
-          ReplayFileSystem fs = await replay();
-          expect(() => fs.currentDirectory = '/bar',
-              throwsNoMatchingInvocationError);
-          fs.currentDirectory = '/foo';
-          expect(() => fs.currentDirectory = '/foo',
-              throwsNoMatchingInvocationError);
-        });
-
-        test('setToDirectory', () async {
-          Directory dir = await recordingFileSystem.directory('/foo').create();
-          recordingFileSystem.currentDirectory = dir;
-          ReplayFileSystem fs = await replay();
-          Directory replayDir = fs.directory('/foo');
-          expect(() => fs.directory('/foo'), throwsNoMatchingInvocationError);
-          fs.currentDirectory = replayDir;
-          expect(() => fs.currentDirectory = replayDir,
-              throwsNoMatchingInvocationError);
-        });
-      });
-
-      test('stat', () async {
-        FileStat stat = await recordingFileSystem.stat('/');
-        ReplayFileSystem fs = await replay();
-        Future<FileStat> replayStatFuture = fs.stat('/');
-        expect(() => fs.stat('/'), throwsNoMatchingInvocationError);
-        expect(replayStatFuture, isFuture);
-        FileStat replayStat = await replayStatFuture;
-        expect(replayStat.accessed, stat.accessed);
-        expect(replayStat.changed, stat.changed);
-        expect(replayStat.modified, stat.modified);
-        expect(replayStat.mode, stat.mode);
-        expect(replayStat.type, stat.type);
-        expect(replayStat.size, stat.size);
-        expect(replayStat.modeString(), stat.modeString());
-      });
-
-      test('statSync', () async {
-        FileStat stat = recordingFileSystem.statSync('/');
-        ReplayFileSystem fs = await replay();
-        FileStat replayStat = fs.statSync('/');
-        expect(() => fs.statSync('/'), throwsNoMatchingInvocationError);
-        expect(replayStat.accessed, stat.accessed);
-        expect(replayStat.changed, stat.changed);
-        expect(replayStat.modified, stat.modified);
-        expect(replayStat.mode, stat.mode);
-        expect(replayStat.type, stat.type);
-        expect(replayStat.size, stat.size);
-        expect(replayStat.modeString(), stat.modeString());
-      });
-
-      test('identical', () async {
-        memoryFileSystem.directory('/foo').createSync();
-        bool identical = await recordingFileSystem.identical('/', '/foo');
-        ReplayFileSystem fs = await replay();
-        Future<bool> replayIdenticalFuture = fs.identical('/', '/foo');
-        expect(
-            () => fs.identical('/', '/foo'), throwsNoMatchingInvocationError);
-        expect(replayIdenticalFuture, isFuture);
-        expect(await replayIdenticalFuture, identical);
-      });
-
-      test('identicalSync', () async {
-        memoryFileSystem.directory('/foo').createSync();
-        bool identical = recordingFileSystem.identicalSync('/', '/foo');
-        ReplayFileSystem fs = await replay();
-        bool replayIdentical = fs.identicalSync('/', '/foo');
-        expect(() => fs.identicalSync('/', '/foo'),
-            throwsNoMatchingInvocationError);
-        expect(replayIdentical, identical);
-      });
-
-      test('isWatchSupported', () async {
-        bool isWatchSupported = recordingFileSystem.isWatchSupported;
-        ReplayFileSystem fs = await replay();
-        expect(fs.isWatchSupported, isWatchSupported);
-        expect(() => fs.isWatchSupported, throwsNoMatchingInvocationError);
-      });
-
-      test('type', () async {
-        FileSystemEntityType type = await recordingFileSystem.type('/');
-        ReplayFileSystem fs = await replay();
-        Future<FileSystemEntityType> replayTypeFuture = fs.type('/');
-        expect(() => fs.type('/'), throwsNoMatchingInvocationError);
-        expect(replayTypeFuture, isFuture);
-        expect(await replayTypeFuture, type);
-      });
-
-      test('typeSync', () async {
-        FileSystemEntityType type = recordingFileSystem.typeSync('/');
-        ReplayFileSystem fs = await replay();
-        FileSystemEntityType replayType = fs.typeSync('/');
-        expect(() => fs.typeSync('/'), throwsNoMatchingInvocationError);
-        expect(replayType, type);
-      });
-    });
-  });
-
-  group('describeInvocation', () {
-    test('methodWithNoArguments', () {
-      expect(
-        describeInvocation(Invocation.method(#foo, <Object>[])),
-        'foo()',
-      );
-    });
-
-    test('methodWithOnlyPositionalArguments', () {
-      expect(
-        describeInvocation(Invocation.method(#foo, <Object>[1, 'bar', null])),
-        'foo(1, "bar", null)',
-      );
-    });
-
-    test('methodWithOnlyNamedArguments', () {
-      expect(
-        describeInvocation(Invocation.method(
-          #foo,
-          <Object>[],
-          <Symbol, Object>{#x: 2, #y: 'baz', #z: null},
-        )),
-        'foo(x: 2, y: "baz", z: null)',
-      );
-    });
-
-    test('methodWithPositionalAndNamedArguments', () {
-      expect(
-        describeInvocation(Invocation.method(
-          #foo,
-          <Object>[1, 'bar', null],
-          <Symbol, Object>{#x: 2, #y: 'baz', #z: null},
-        )),
-        'foo(1, "bar", null, x: 2, y: "baz", z: null)',
-      );
-    });
-
-    test('setter', () {
-      expect(
-        describeInvocation(Invocation.setter(#property, 'value')),
-        'property = "value"',
-      );
-    });
-  });
-}
-
-/// Successfully matches against an instance of [Future].
-const Matcher isFuture = TypeMatcher<Future<dynamic>>();