Skip to content

Migrate frontend-server-common to null safety #1650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
3 changes: 3 additions & 0 deletions frontend_server_common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.2.0
- Migrate to null safety

## 0.1.1
- Remove dead code

Expand Down
89 changes: 46 additions & 43 deletions frontend_server_common/lib/src/asset_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.9

// Note: this is a copy from flutter tools, updated to work with dwds tests

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:dwds/dwds.dart';
import 'package:dwds/asset_reader.dart';
import 'package:file/file.dart';
import 'package:logging/logging.dart';
import 'package:mime/mime.dart' as mime;
Expand All @@ -32,10 +30,10 @@ class TestAssetServer implements AssetReader {
static const String _defaultMimeType = 'application/octet-stream';
final FileSystem _fileSystem;
final HttpServer _httpServer;
final Map<String, Uint8List> _files = <String, Uint8List>{};
final Map<String, Uint8List> _sourcemaps = <String, Uint8List>{};
final Map<String, Uint8List> _metadata = <String, Uint8List>{};
String _mergedMetadata;
final Map<String, Uint8List> _files = {};
final Map<String, Uint8List> _sourceMaps = {};
final Map<String, Uint8List> _metadata = {};
late String _mergedMetadata;
final PackageConfig _packageConfig;
final InternetAddress internetAddress;

Expand All @@ -47,6 +45,15 @@ class TestAssetServer implements AssetReader {
this._fileSystem,
) : basePath = _parseBasePathFromIndexHtml(index);

bool hasFile(String path) => _files.containsKey(path);
Uint8List getFile(String path) => _files[path]!;

bool hasSourceMap(String path) => _sourceMaps.containsKey(path);
Uint8List getSourceMap(String path) => _sourceMaps[path]!;

bool hasMetadata(String path) => _metadata.containsKey(path);
Uint8List getMetadata(String path) => _metadata[path]!;

/// Start the web asset server on a [hostname] and [port].
///
/// Unhandled exceptions will throw a exception with the error and stack
Expand All @@ -66,10 +73,6 @@ class TestAssetServer implements AssetReader {
return server;
}

Uint8List getFile(String path) => _files[path];

Uint8List getSourceMap(String path) => _sourcemaps[path];

// handle requests for JavaScript source, dart sources maps, or asset files.
Future<shelf.Response> handleRequest(shelf.Request request) async {
var headers = <String, String>{};
Expand All @@ -94,21 +97,18 @@ class TestAssetServer implements AssetReader {
requestPath = _stripBasePath(requestPath, basePath) ?? requestPath;

requestPath = requestPath.startsWith('/') ? requestPath : '/$requestPath';
if (requestPath == null) {
return shelf.Response.notFound('');
}

// If this is a JavaScript file, it must be in the in-memory cache.
// Attempt to look up the file by URI.
if (_files.containsKey(requestPath)) {
if (hasFile(requestPath)) {
final List<int> bytes = getFile(requestPath);
headers[HttpHeaders.contentLengthHeader] = bytes.length.toString();
headers[HttpHeaders.contentTypeHeader] = 'application/javascript';
return shelf.Response.ok(bytes, headers: headers);
}
// If this is a sourcemap file, then it might be in the in-memory cache.
// Attempt to lookup the file by URI.
if (_sourcemaps.containsKey(requestPath)) {
if (hasSourceMap(requestPath)) {
final List<int> bytes = getSourceMap(requestPath);
headers[HttpHeaders.contentLengthHeader] = bytes.length.toString();
headers[HttpHeaders.contentTypeHeader] = 'application/json';
Expand All @@ -124,7 +124,7 @@ class TestAssetServer implements AssetReader {
// Attempt to determine the file's mime type. if this is not provided some
// browsers will refuse to render images/show video et cetera. If the tool
// cannot determine a mime type, fall back to application/octet-stream.
String mimeType;
String? mimeType;
if (length >= 12) {
mimeType = mime.lookupMimeType(
file.path,
Expand Down Expand Up @@ -160,10 +160,6 @@ class TestAssetServer implements AssetReader {
var manifest =
_castStringKeyedMap(json.decode(manifestFile.readAsStringSync()));
for (var filePath in manifest.keys) {
if (filePath == null) {
_logger.severe('Invalid manfiest file: $filePath');
continue;
}
var offsets = _castStringKeyedMap(manifest[filePath]);
var codeOffsets = (offsets['code'] as List<dynamic>).cast<int>();
var sourcemapOffsets =
Expand Down Expand Up @@ -200,7 +196,7 @@ class TestAssetServer implements AssetReader {
sourcemapStart,
sourcemapEnd - sourcemapStart,
);
_sourcemaps['$filePath.map'] = sourcemapView;
_sourceMaps['$filePath.map'] = sourcemapView;

var metadataStart = metadataOffsets[0];
var metadataEnd = metadataOffsets[1];
Expand Down Expand Up @@ -259,36 +255,42 @@ class TestAssetServer implements AssetReader {
}

@override
Future<String> dartSourceContents(String serverPath) {
serverPath = _stripBasePath(serverPath, basePath);
var result = _resolveDartFile(serverPath);
if (result.existsSync()) {
return result.readAsString();
Future<String?> dartSourceContents(String serverPath) async {
final stripped = _stripBasePath(serverPath, basePath);
if (stripped != null) {
var result = _resolveDartFile(stripped);
if (result.existsSync()) {
return result.readAsString();
}
}
_logger.severe('Source not found: $serverPath');
return null;
}

@override
Future<String> sourceMapContents(String serverPath) async {
serverPath = _stripBasePath(serverPath, basePath);
var path = '/$serverPath';
if (_sourcemaps.containsKey(path)) {
return utf8.decode(_sourcemaps[path]);
Future<String?> sourceMapContents(String serverPath) async {
final stripped = _stripBasePath(serverPath, basePath);
if (stripped != null) {
var path = '/$stripped';
if (hasSourceMap(path)) {
return utf8.decode(getSourceMap(path));
}
}
_logger.severe('Source map not found: $serverPath');
return null;
}

@override
Future<String> metadataContents(String serverPath) async {
serverPath = _stripBasePath(serverPath, basePath);
if (serverPath.endsWith('.ddc_merged_metadata')) {
return _mergedMetadata;
}
var path = '/$serverPath';
if (_metadata.containsKey(path)) {
return utf8.decode(_metadata[path]);
Future<String?> metadataContents(String serverPath) async {
final stripped = _stripBasePath(serverPath, basePath);
if (stripped != null) {
if (stripped.endsWith('.ddc_merged_metadata')) {
return _mergedMetadata;
}
var path = '/$stripped';
if (hasMetadata(path)) {
return utf8.decode(getMetadata(path));
}
}
_logger.severe('Metadata not found: $serverPath');
return null;
Expand All @@ -299,7 +301,7 @@ class TestAssetServer implements AssetReader {
/// the same structure (`Map<String, dynamic>`) with the correct runtime types.
Map<String, dynamic> _castStringKeyedMap(dynamic untyped) {
var map = untyped as Map<dynamic, dynamic>;
return map?.cast<String, dynamic>();
return map.cast<String, dynamic>();
}

String _stripLeadingSlashes(String path) {
Expand All @@ -309,7 +311,7 @@ String _stripLeadingSlashes(String path) {
return path;
}

String _stripBasePath(String path, String basePath) {
String? _stripBasePath(String path, String basePath) {
path = _stripLeadingSlashes(path);
if (path.startsWith(basePath)) {
path = path.substring(basePath.length);
Expand All @@ -327,5 +329,6 @@ String _parseBasePathFromIndexHtml(String index) {
}
final contents = file.readAsStringSync();
final matches = RegExp(r'<base href="/([^>]*)/">').allMatches(contents);
return matches.isEmpty ? '' : matches.first.group(1);
if (matches.isEmpty) return '';
return matches.first.group(1) ?? '';
}
12 changes: 4 additions & 8 deletions frontend_server_common/lib/src/bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.9

// Note: this is a copy from flutter tools, updated to work with dwds tests

import 'package:meta/meta.dart';

/// The JavaScript bootstrap script to support in-browser hot restart.
///
/// The [requireUrl] loads our cached RequireJS script file. The [mapperUrl]
Expand All @@ -18,9 +14,9 @@ import 'package:meta/meta.dart';
/// and is responsible for bootstrapping the RequireJS modules and attaching
/// the hot reload hooks.
String generateBootstrapScript({
@required String requireUrl,
@required String mapperUrl,
@required String entrypoint,
required String requireUrl,
required String mapperUrl,
required String entrypoint,
}) {
return '''
"use strict";
Expand Down Expand Up @@ -53,7 +49,7 @@ document.head.appendChild(requireEl);
/// the file `foo/bar/baz.dart` will generate a property named approximately
/// `foo__bar__baz`. Rather than attempt to guess, we assume the first property of
/// this object is the module.
String generateMainModule({@required String entrypoint}) {
String generateMainModule({required String entrypoint}) {
return '''/* ENTRYPOINT_EXTENTION_MARKER */

// Create the main module loaded below.
Expand Down
43 changes: 18 additions & 25 deletions frontend_server_common/lib/src/devfs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.9

// Note: this is a copy from flutter tools, updated to work with dwds tests

import 'dart:io';

import 'package:dwds/dwds.dart';
import 'package:dwds/asset_reader.dart';
import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import 'package:path/path.dart' as p;

Expand All @@ -23,28 +20,27 @@ final String dartWebSdkPath = p.join(dartSdkPath, 'lib', 'dev_compiler');

class WebDevFS {
WebDevFS({
this.fileSystem,
this.hostname,
this.port,
this.projectDirectory,
this.packageConfigFile,
this.index,
this.urlTunneller,
this.soundNullSafety,
required this.fileSystem,
required this.hostname,
required this.port,
required this.projectDirectory,
required this.packageConfigFile,
required this.index,
required this.urlTunneller,
required this.soundNullSafety,
});

final FileSystem fileSystem;
TestAssetServer assetServer;
late final TestAssetServer assetServer;
final String hostname;
final int port;
final Uri projectDirectory;
final Uri packageConfigFile;
final String index;
final UrlEncoder urlTunneller;
final bool soundNullSafety;
Directory _savedCurrentDirectory;
List<Uri> sources;
PackageConfig _packageConfig;
late final Directory _savedCurrentDirectory;
late final PackageConfig _packageConfig;

Future<Uri> create() async {
_savedCurrentDirectory = fileSystem.currentDirectory;
Expand All @@ -61,16 +57,15 @@ class WebDevFS {

Future<void> dispose() {
fileSystem.currentDirectory = _savedCurrentDirectory;
return assetServer?.close();
return assetServer.close();
}

Future<UpdateFSReport> update({
Uri mainUri,
String dillOutputPath,
@required ResidentCompiler generator,
List<Uri> invalidatedFiles,
required Uri mainUri,
required String dillOutputPath,
required ResidentCompiler generator,
required List<Uri> invalidatedFiles,
}) async {
assert(generator != null);
final mainPath = mainUri.toFilePath();
final outputDirectoryPath = fileSystem.file(mainPath).parent.path;
final entryPoint = mainUri.toString();
Expand Down Expand Up @@ -108,8 +103,6 @@ class WebDevFS {
return UpdateFSReport(success: false);
}

// list of sources that needs to be monitored are in [compilerOutput.sources]
sources = compilerOutput.sources;
File codeFile;
File manifestFile;
File sourcemapFile;
Expand Down Expand Up @@ -200,7 +193,7 @@ class UpdateFSReport {
/// mode.
///
/// Only used for JavaScript compilation.
List<String> invalidatedModules;
List<String>? invalidatedModules;
}

String _filePathToUriFragment(String path) {
Expand Down
Loading