Migrate to null safety (#47)
Fixes #41
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index 779e3d2..2ae7ee0 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -58,27 +58,3 @@
- name: Run VM tests
run: dart test --platform vm
if: always() && steps.install.outcome == 'success'
-
- # Run tests on a matrix consisting of two dimensions:
- # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
- # 2. release channel: 2.3.0
- test-legacy-sdk:
- needs: analyze
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- # Add macos-latest and/or windows-latest if relevant for this package.
- os: [ubuntu-latest]
- sdk: [2.3.0]
- steps:
- - uses: actions/checkout@v2
- - uses: dart-lang/setup-dart@v0.3
- with:
- sdk: ${{ matrix.sdk }}
- - id: install
- name: Install dependencies
- run: pub get
- - name: Run VM tests
- run: pub run test --platform vm
- if: always() && steps.install.outcome == 'success'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 040c4d2..ab642b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
+## 1.0.0-dev
+
+* Migrate to null safety.
+
## 0.2.9+2
-- Change version constraint for the `shelf` dependency, so it accepts null-safe versions.
+* Change version constraint for the `shelf` dependency, so it accepts null-safe versions.
## 0.2.9+1
diff --git a/example/example_server.dart b/example/example_server.dart
index 11dd0b3..288d630 100644
--- a/example/example_server.dart
+++ b/example/example_server.dart
@@ -23,8 +23,7 @@
logging = result['logging'] as bool;
listDirectories = result['list-directories'] as bool;
} on FormatException catch (e) {
- stderr.writeln(e.message);
- stderr.writeln(parser.usage);
+ stderr..writeln(e.message)..writeln(parser.usage);
// http://linux.die.net/include/sysexits.h
// #define EX_USAGE 64 /* command line usage error */
exit(64);
@@ -40,7 +39,7 @@
pipeline = pipeline.addMiddleware(shelf.logRequests());
}
- var defaultDoc = _defaultDoc;
+ String? defaultDoc = _defaultDoc;
if (listDirectories) {
defaultDoc = null;
}
diff --git a/lib/src/static_handler.dart b/lib/src/static_handler.dart
index e1545a0..23ac17f 100644
--- a/lib/src/static_handler.dart
+++ b/lib/src/static_handler.dart
@@ -41,10 +41,10 @@
/// detection.
Handler createStaticHandler(String fileSystemPath,
{bool serveFilesOutsidePath = false,
- String defaultDocument,
+ String? defaultDocument,
bool listDirectories = false,
bool useHeaderBytesForContentType = false,
- MimeTypeResolver contentTypeResolver}) {
+ MimeTypeResolver? contentTypeResolver}) {
final rootDir = Directory(fileSystemPath);
if (!rootDir.existsSync()) {
throw ArgumentError('A directory corresponding to fileSystemPath '
@@ -59,31 +59,32 @@
}
}
- contentTypeResolver ??= _defaultMimeTypeResolver;
+ final mimeResolver = contentTypeResolver ?? _defaultMimeTypeResolver;
return (Request request) {
final segs = [fileSystemPath, ...request.url.pathSegments];
final fsPath = p.joinAll(segs);
- final entityType = FileSystemEntity.typeSync(fsPath, followLinks: true);
+ final entityType = FileSystemEntity.typeSync(fsPath);
- File file;
+ File? fileFound;
if (entityType == FileSystemEntityType.file) {
- file = File(fsPath);
+ fileFound = File(fsPath);
} else if (entityType == FileSystemEntityType.directory) {
- file = _tryDefaultFile(fsPath, defaultDocument);
- if (file == null && listDirectories) {
+ fileFound = _tryDefaultFile(fsPath, defaultDocument);
+ if (fileFound == null && listDirectories) {
final uri = request.requestedUri;
if (!uri.path.endsWith('/')) return _redirectToAddTrailingSlash(uri);
return listDirectory(fileSystemPath, fsPath);
}
}
- if (file == null) {
+ if (fileFound == null) {
return Response.notFound('Not Found');
}
+ final file = fileFound;
if (!serveFilesOutsidePath) {
final resolvedPath = file.resolveSymbolicLinksSync();
@@ -104,17 +105,16 @@
return _handleFile(request, file, () async {
if (useHeaderBytesForContentType) {
- final length = math.min(
- contentTypeResolver.magicNumbersMaxLength, file.lengthSync());
+ final length =
+ math.min(mimeResolver.magicNumbersMaxLength, file.lengthSync());
final byteSink = ByteAccumulatorSink();
await file.openRead(0, length).listen(byteSink.add).asFuture();
- return contentTypeResolver.lookup(file.path,
- headerBytes: byteSink.bytes);
+ return mimeResolver.lookup(file.path, headerBytes: byteSink.bytes);
} else {
- return contentTypeResolver.lookup(file.path);
+ return mimeResolver.lookup(file.path);
}
});
};
@@ -132,7 +132,7 @@
return Response.movedPermanently(location.toString());
}
-File _tryDefaultFile(String dirPath, String defaultFile) {
+File? _tryDefaultFile(String dirPath, String? defaultFile) {
if (defaultFile == null) return null;
final filePath = p.join(dirPath, defaultFile);
@@ -154,7 +154,7 @@
/// This uses the given [contentType] for the Content-Type header. It defaults
/// to looking up a content type based on [path]'s file extension, and failing
/// that doesn't sent a [contentType] header at all.
-Handler createFileHandler(String path, {String url, String contentType}) {
+Handler createFileHandler(String path, {String? url, String? contentType}) {
final file = File(path);
if (!file.existsSync()) {
throw ArgumentError.value(path, 'path', 'does not exist.');
@@ -162,12 +162,12 @@
throw ArgumentError.value(url, 'url', 'must be relative.');
}
- contentType ??= _defaultMimeTypeResolver.lookup(path);
+ final mimeType = contentType ?? _defaultMimeTypeResolver.lookup(path);
url ??= p.toUri(p.basename(path)).toString();
return (request) {
if (request.url.path != url) return Response.notFound('Not Found');
- return _handleFile(request, file, () => contentType);
+ return _handleFile(request, file, () => mimeType);
};
}
@@ -177,7 +177,7 @@
/// indicates that it has the latest version of a file. Otherwise, it calls
/// [getContentType] and uses it to populate the Content-Type header.
Future<Response> _handleFile(Request request, File file,
- FutureOr<String> Function() getContentType) async {
+ FutureOr<String?> Function() getContentType) async {
final stat = file.statSync();
final ifModifiedSince = request.ifModifiedSince;
diff --git a/pubspec.yaml b/pubspec.yaml
index f828265..e945e97 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,19 +1,23 @@
name: shelf_static
-version: 0.2.9+2
+version: 1.0.0-dev
description: Static file server support for shelf
repository: https://github.com/dart-lang/shelf_static
environment:
- sdk: '>=2.3.0 <3.0.0'
+ sdk: '>=2.12.0-0 <3.0.0'
dependencies:
- convert: '>=1.0.0 <4.0.0'
- http_parser: '>=0.0.2+2 <5.0.0'
- mime: '>=0.9.0 <=1.0.0'
- path: '>=1.1.0 <2.0.0'
- shelf: '>=0.5.7 <2.0.0'
+ convert: ^3.0.0
+ http_parser: ^4.0.0
+ mime: ^1.0.0
+ path: ^1.8.0
+ shelf: ^1.0.0
dev_dependencies:
- args: '^1.0.0'
- test: '^1.2.0'
- test_descriptor: '^1.0.0'
+ args: ^2.0.0
+ test: ^1.16.0
+ test_descriptor: ^2.0.0
+
+dependency_overrides:
+ shelf_packages_handler: ^2.0.1
+ test: ^1.16.0
diff --git a/test/basic_file_test.dart b/test/basic_file_test.dart
index ec5ab46..ab89efc 100644
--- a/test/basic_file_test.dart
+++ b/test/basic_file_test.dart
@@ -153,7 +153,7 @@
final rootPath = p.join(d.sandbox, 'root.txt');
final response1 = await makeRequest(handler, '/root.txt');
- final originalModificationDate = response1.lastModified;
+ final originalModificationDate = response1.lastModified!;
// Ensure the timestamp change is > 1s.
await Future<void>.delayed(const Duration(seconds: 2));
@@ -167,7 +167,7 @@
final response2 =
await makeRequest(handler, '/root.txt', headers: headers);
expect(response2.statusCode, HttpStatus.ok);
- expect(response2.lastModified.millisecondsSinceEpoch,
+ expect(response2.lastModified!.millisecondsSinceEpoch,
greaterThan(originalModificationDate.millisecondsSinceEpoch));
});
});
diff --git a/test/test_util.dart b/test/test_util.dart
index f42f6d1..e496394 100644
--- a/test/test_util.dart
+++ b/test/test_util.dart
@@ -11,15 +11,15 @@
/// Makes a simple GET request to [handler] and returns the result.
Future<Response> makeRequest(Handler handler, String path,
- {String handlerPath, Map<String, String> headers}) {
+ {String? handlerPath, Map<String, String>? headers}) {
final rootedHandler = _rootHandler(handlerPath, handler);
return Future.sync(() => rootedHandler(_fromPath(path, headers)));
}
-Request _fromPath(String path, Map<String, String> headers) =>
+Request _fromPath(String path, Map<String, String>? headers) =>
Request('GET', Uri.parse('http://localhost$path'), headers: headers);
-Handler _rootHandler(String path, Handler handler) {
+Handler _rootHandler(String? path, Handler handler) {
if (path == null || path.isEmpty) {
return handler;
}
@@ -49,7 +49,7 @@
bool matches(dynamic item, Map matchState) {
if (item is! DateTime) return false;
- return _datesEqualToSecond(_target, item as DateTime);
+ return _datesEqualToSecond(_target, item);
}
@override