Support compilation to JS
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cea4456..f87e418 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.5.2
+
+- This package now supports being compiled to JavaScript.
+
 ## 0.5.1
 
 - Improve performance when reading large archives
diff --git a/dart_test.yaml b/dart_test.yaml
new file mode 100644
index 0000000..626963c
--- /dev/null
+++ b/dart_test.yaml
@@ -0,0 +1,3 @@
+platforms:
+  - "vm"
+  - "node"
diff --git a/lib/src/constants.dart b/lib/src/constants.dart
index aac7669..05accb0 100644
--- a/lib/src/constants.dart
+++ b/lib/src/constants.dart
@@ -216,13 +216,6 @@
 /// Sticky bit
 const c_ISVTX = 512;
 
-/// **********************
-///  Convenience constants
-/// **********************
-/// 64-bit integer max and min values
-const int64MaxValue = 9223372036854775807;
-const int64MinValue = -9223372036854775808;
-
 /// Constants to determine file modes.
 const modeType = 2401763328;
 const modeSymLink = 134217728;
diff --git a/pubspec.yaml b/pubspec.yaml
index 06a3bd7..d0ed1ba 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: tar
 description: Memory-efficient, streaming implementation of the tar file format
-version: 0.5.1
+version: 0.5.2
 repository: https://github.com/simolus3/tar/
 
 environment:
@@ -14,5 +14,7 @@
 dev_dependencies:
   charcode: ^1.2.0
   extra_pedantic: ^1.4.0
+  file: ^6.1.2
+  node_io: ^2.1.0
   path: ^1.8.0
   test: ^1.17.4
diff --git a/test/pub_test.dart b/test/pub_test.dart
index 756ee09..ecbcbc0 100644
--- a/test/pub_test.dart
+++ b/test/pub_test.dart
@@ -3,6 +3,7 @@
 // The test cases were found by running an earlier version of this package
 // across all packages and versions found on pub.dev. This package needs to
 // be able to read every package version ever uploaded to pub.
+@TestOn('vm')
 import 'dart:io';
 
 import 'package:tar/tar.dart';
diff --git a/test/reader_test.dart b/test/reader_test.dart
index 7ea558c..89c5d81 100644
--- a/test/reader_test.dart
+++ b/test/reader_test.dart
@@ -1,6 +1,5 @@
 import 'dart:async';
 import 'dart:convert';
-import 'dart:io';
 import 'dart:typed_data';
 
 import 'package:async/async.dart';
@@ -9,6 +8,8 @@
 import 'package:tar/tar.dart';
 import 'package:test/test.dart';
 
+import 'utils.dart';
+
 void main() {
   group('POSIX.1-2001', () {
     test('reads files', () => _testWith('reference/posix.tar'));
@@ -22,7 +23,7 @@
   test('v7', () => _testWith('reference/v7.tar', ignoreLongFileName: true));
 
   test('can skip tar files', () async {
-    final input = File('reference/posix.tar').openRead();
+    final input = fs.file('reference/posix.tar').openRead();
     final reader = TarReader(input);
 
     expect(await reader.moveNext(), isTrue);
@@ -46,7 +47,7 @@
   });
 
   test("can't use moveNext() while a stream is active", () async {
-    final input = File('reference/posix.tar').openRead();
+    final input = fs.file('reference/posix.tar').openRead();
     final reader = TarReader(input);
 
     expect(await reader.moveNext(), isTrue);
@@ -57,7 +58,7 @@
   });
 
   test("can't use moveNext() after canceling the reader", () async {
-    final input = File('reference/posix.tar').openRead();
+    final input = fs.file('reference/posix.tar').openRead();
     final reader = TarReader(input);
     await reader.cancel();
 
@@ -97,7 +98,8 @@
     test('if the stream emits an error in content', () async {
       // Craft a stream that starts with a valid tar file, but then emits an
       // error in the middle of an entry. First 512 bytes are headers.
-      final iterator = ChunkedStreamReader(File('reference/v7.tar').openRead());
+      final iterator =
+          ChunkedStreamReader(fs.file('reference/v7.tar').openRead());
       final controller = StreamController<List<int>>();
       controller.onListen = () async {
         // headers + 3 bytes of content
@@ -181,7 +183,7 @@
 
   group('tests from dart-neats PR', () {
     Stream<List<int>> open(String name) {
-      return File('reference/neats_test/$name').openRead();
+      return fs.file('reference/neats_test/$name').openRead();
     }
 
     final tests = [
@@ -858,8 +860,8 @@
   });
 
   test('does not read large headers', () {
-    final reader =
-        TarReader(File('reference/headers/evil_large_header.tar').openRead());
+    final reader = TarReader(
+        fs.file('reference/headers/evil_large_header.tar').openRead());
 
     expect(
       reader.moveNext(),
@@ -875,14 +877,14 @@
         .having((e) => e.message, 'message', contains('Unexpected end'));
 
     test('at header', () {
-      final reader =
-          TarReader(File('reference/bad/truncated_in_header.tar').openRead());
+      final reader = TarReader(
+          fs.file('reference/bad/truncated_in_header.tar').openRead());
       expect(reader.moveNext(), throwsA(expectedException));
     });
 
     test('in content', () {
       final reader =
-          TarReader(File('reference/bad/truncated_in_body.tar').openRead());
+          TarReader(fs.file('reference/bad/truncated_in_body.tar').openRead());
       expect(reader.moveNext(), throwsA(expectedException));
     });
   });
@@ -949,7 +951,7 @@
 Future<void> _testWith(String file, {bool ignoreLongFileName = false}) async {
   final entries = <String, Uint8List>{};
 
-  await TarReader.forEach(File(file).openRead(), (entry) async {
+  await TarReader.forEach(fs.file(file).openRead(), (entry) async {
     entries[entry.name] = await entry.contents.readFully();
   });
 
@@ -965,7 +967,7 @@
 }
 
 Future<void> _testLargeFile(String file) async {
-  final reader = TarReader(File(file).openRead());
+  final reader = TarReader(fs.file(file).openRead());
   await reader.moveNext();
 
   expect(reader.current.size, 9663676416);
diff --git a/test/sparse_test.dart b/test/sparse_test.dart
index de92dba..6729ae0 100644
--- a/test/sparse_test.dart
+++ b/test/sparse_test.dart
@@ -1,4 +1,4 @@
-@TestOn('linux') // We currently use gnu tar to create test inputs
+@TestOn('linux && vm') // We currently use gnu tar to create test inputs
 import 'dart:io';
 
 import 'dart:math';
diff --git a/test/system_tar.dart b/test/system_tar.dart
index 4022870..c983896 100644
--- a/test/system_tar.dart
+++ b/test/system_tar.dart
@@ -17,7 +17,7 @@
     final sink = ByteConversionSink.withCallback((result) => data = result);
     proc.stderr.forEach(sink.add).then((Object? _) {
       sink.close();
-      const LineSplitter().convert(utf8.decode(data)).forEach(stderr.writeln);
+      const LineSplitter().convert(utf8.decode(data)).forEach(print);
     });
 
     return proc;
diff --git a/test/utils.dart b/test/utils.dart
new file mode 100644
index 0000000..0149de1
--- /dev/null
+++ b/test/utils.dart
@@ -0,0 +1,3 @@
+export 'package:file/file.dart';
+
+export 'utils_vm.dart' if (dart.library.js) 'utils_node.dart';
diff --git a/test/utils_node.dart b/test/utils_node.dart
new file mode 100644
index 0000000..61a2af4
--- /dev/null
+++ b/test/utils_node.dart
@@ -0,0 +1,7 @@
+import 'package:file/file.dart';
+
+import 'package:node_io/node_io.dart';
+
+FileSystem get fs {
+  return nodeFileSystem;
+}
diff --git a/test/utils_test.dart b/test/utils_test.dart
index 4462e60..93af4e8 100644
--- a/test/utils_test.dart
+++ b/test/utils_test.dart
@@ -1,3 +1,4 @@
+@TestOn('vm')
 import 'dart:async';
 import 'dart:convert';
 import 'dart:typed_data';
diff --git a/test/utils_vm.dart b/test/utils_vm.dart
new file mode 100644
index 0000000..b24f6f1
--- /dev/null
+++ b/test/utils_vm.dart
@@ -0,0 +1,6 @@
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+
+FileSystem get fs {
+  return const LocalFileSystem();
+}
diff --git a/test/windows_integration_test.dart b/test/windows_integration_test.dart
index ed7f9f2..9a02bad 100644
--- a/test/windows_integration_test.dart
+++ b/test/windows_integration_test.dart
@@ -1,4 +1,4 @@
-@TestOn('windows')
+@TestOn('windows && vm')
 import 'dart:io';
 
 import 'package:tar/tar.dart';
diff --git a/test/writer_test.dart b/test/writer_test.dart
index c6b23fc..a026432 100644
--- a/test/writer_test.dart
+++ b/test/writer_test.dart
@@ -1,3 +1,4 @@
+@TestOn('vm')
 import 'dart:async';
 import 'dart:convert';
 import 'dart:typed_data';
@@ -136,7 +137,7 @@
 
     final proc = await writeToTar(['--list', '--verbose'], Stream.value(entry));
     expect(proc.lines, emits(contains(tenGbSize.toString())));
-  }, testOn: '!windows');
+  }, testOn: '!windows && !node');
 
   group('refuses to write files with OutputFormat.gnu', () {
     void shouldThrow(tar.TarEntry entry) {