diff --git a/dwds/lib/src/debugging/metadata/function.dart b/dwds/lib/src/debugging/metadata/function.dart index f252624dd..bc435a0b8 100644 --- a/dwds/lib/src/debugging/metadata/function.dart +++ b/dwds/lib/src/debugging/metadata/function.dart @@ -2,8 +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.import 'dart:async'; -// @dart = 2.9 - import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import '../../loaders/strategy.dart'; @@ -43,8 +41,9 @@ class FunctionMetaData { response, evalContents: evalExpression, ); - var name = response.result['result']['value'] as String; - if (name.isEmpty) name = 'Closure'; + final name = response.result?['result']?['value'] as String?; + if (name == null) return FunctionMetaData(''); + if (name.isEmpty) return FunctionMetaData('Closure'); return FunctionMetaData(name); } } diff --git a/dwds/lib/src/debugging/metadata/module_metadata.dart b/dwds/lib/src/debugging/metadata/module_metadata.dart index 2bf2c693b..fffd5916e 100644 --- a/dwds/lib/src/debugging/metadata/module_metadata.dart +++ b/dwds/lib/src/debugging/metadata/module_metadata.dart @@ -2,8 +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.9 - /// Module metadata format version /// /// Module reader always creates the current version but is able to read @@ -77,10 +75,9 @@ class LibraryMetadata { LibraryMetadata(this.name, this.importUri, this.partUris); LibraryMetadata.fromJson(Map json) - : name = json['name'] as String, - importUri = json['importUri'] as String, - partUris = - List.castFrom(json['partUris'] as List); + : name = _readRequiredField(json, 'name'), + importUri = _readRequiredField(json, 'importUri'), + partUris = _readOptionalList(json, 'partUris') ?? []; Map toJson() { return { @@ -98,7 +95,7 @@ class LibraryMetadata { /// See: https://goto.google.com/dart-web-debugger-metadata class ModuleMetadata { /// Metadata format version - String version; + late final String version; /// Module name /// @@ -125,8 +122,8 @@ class ModuleMetadata { ModuleMetadata(this.name, this.closureName, this.sourceMapUri, this.moduleUri, this.soundNullSafety, - {this.version}) { - version ??= ModuleMetadataVersion.current.version; + {String? ver}) { + version = ver ?? ModuleMetadataVersion.current.version; } /// Add [library] to metadata @@ -145,12 +142,12 @@ class ModuleMetadata { } ModuleMetadata.fromJson(Map json) - : version = json['version'] as String, - name = json['name'] as String, - closureName = json['closureName'] as String, - sourceMapUri = json['sourceMapUri'] as String, - moduleUri = json['moduleUri'] as String, - soundNullSafety = (json['soundNullSafety'] as bool) ?? false { + : version = _readRequiredField(json, 'version'), + name = _readRequiredField(json, 'name'), + closureName = _readRequiredField(json, 'closureName'), + sourceMapUri = _readRequiredField(json, 'sourceMapUri'), + moduleUri = _readRequiredField(json, 'moduleUri'), + soundNullSafety = _readOptionalField(json, 'soundNullSafety') ?? false { if (!ModuleMetadataVersion.current.isCompatibleWith(version) && !ModuleMetadataVersion.previous.isCompatibleWith(version)) { throw Exception('Unsupported metadata version $version. ' @@ -159,7 +156,7 @@ class ModuleMetadata { '\n ${ModuleMetadataVersion.previous.version}'); } - for (var l in json['libraries'] as List) { + for (var l in _readRequiredList(json, 'libraries')) { addLibrary(LibraryMetadata.fromJson(l as Map)); } } @@ -176,3 +173,23 @@ class ModuleMetadata { }; } } + +T _readRequiredField(Map json, String field) { + if (!json.containsKey(field)) { + throw FormatException('Required field $field is not set in $json'); + } + return json[field]! as T; +} + +T? _readOptionalField(Map json, String field) => + json[field] as T?; + +List _readRequiredList(Map json, String field) { + final list = _readRequiredField>(json, field); + return List.castFrom(list); +} + +List? _readOptionalList(Map json, String field) { + final list = _readOptionalField>(json, field); + return list == null ? null : List.castFrom(list); +} diff --git a/dwds/lib/src/debugging/metadata/provider.dart b/dwds/lib/src/debugging/metadata/provider.dart index 822ac4715..ae4696e5b 100644 --- a/dwds/lib/src/debugging/metadata/provider.dart +++ b/dwds/lib/src/debugging/metadata/provider.dart @@ -2,8 +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.import 'dart:async'; -// @dart = 2.9 - import 'dart:async'; import 'dart:convert'; @@ -194,8 +192,7 @@ class MetadataProvider { _addSdkMetadata(); for (var contents in merged.split('\n')) { try { - if (contents == null || - contents.isEmpty || + if (contents.isEmpty || contents.startsWith('// intentionally empty:')) continue; final moduleJson = json.decode(contents); final metadata = @@ -237,7 +234,7 @@ class MetadataProvider { for (var path in library.partUris) { // Parts in metadata are relative to the library Uri directory. final partPath = p.url.join(p.dirname(library.importUri), path); - _scripts[library.importUri].add(partPath); + _scripts[library.importUri]!.add(partPath); _scriptToModule[partPath] = metadata.name; } } diff --git a/dwds/lib/src/handlers/injector.dart b/dwds/lib/src/handlers/injector.dart index dfdff18de..4016eaf49 100644 --- a/dwds/lib/src/handlers/injector.dart +++ b/dwds/lib/src/handlers/injector.dart @@ -123,7 +123,10 @@ class DwdsInjector { return response.change(body: body, headers: newHeaders); } else { final loadResponse = await _loadStrategy.handler(request); - if (loadResponse != null) return loadResponse; + if (loadResponse != null && + loadResponse.statusCode != HttpStatus.notFound) { + return loadResponse; + } return innerHandler(request); } }; diff --git a/dwds/lib/src/loaders/build_runner_require.dart b/dwds/lib/src/loaders/build_runner_require.dart index ddcf66c9f..b679e21bf 100644 --- a/dwds/lib/src/loaders/build_runner_require.dart +++ b/dwds/lib/src/loaders/build_runner_require.dart @@ -2,11 +2,10 @@ // 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.9 - import 'dart:convert'; import 'dart:io'; +import 'package:logging/logging.dart'; import 'package:path/path.dart' as p; import 'package:shelf/shelf.dart'; @@ -18,26 +17,28 @@ import 'require.dart'; /// Provides a [RequireStrategy] suitable for use with `package:build_runner`. class BuildRunnerRequireStrategyProvider { + final _logger = Logger('BuildRunnerRequireStrategyProvider'); + final Handler _assetHandler; final ReloadConfiguration _configuration; final AssetReader _assetReader; - RequireStrategy _requireStrategy; + late final RequireStrategy _requireStrategy = RequireStrategy( + _configuration, + _moduleProvider, + _digestsProvider, + _moduleForServerPath, + _serverPathForModule, + _sourceMapPathForModule, + _serverPathForAppUri, + _moduleInfoForProvider, + _assetReader, + ); BuildRunnerRequireStrategyProvider( this._assetHandler, this._configuration, this._assetReader); - RequireStrategy get strategy => _requireStrategy ??= RequireStrategy( - _configuration, - _moduleProvider, - _digestsProvider, - _moduleForServerPath, - _serverPathForModule, - _sourceMapPathForModule, - _serverPathForAppUri, - _moduleInfoForProvider, - _assetReader, - ); + RequireStrategy get strategy => _requireStrategy; Future> _digestsProvider( MetadataProvider metadataProvider) async { @@ -51,9 +52,18 @@ class BuildRunnerRequireStrategyProvider { throw StateError('Could not read digests at path: $digestsPath'); } final body = await response.readAsString(); + final digests = json.decode(body) as Map; + + for (final key in digests.keys) { + if (!modules.containsKey(key)) { + _logger.warning('Digest key $key is not a module name.'); + } + } + return { - for (var entry in (json.decode(body) as Map).entries) - modules[entry.key]: entry.value as String, + for (var entry in digests.entries) + if (modules.containsKey(entry.key)) + modules[entry.key]!: entry.value as String, }; } @@ -62,10 +72,17 @@ class BuildRunnerRequireStrategyProvider { (await metadataProvider.moduleToModulePath).map((key, value) => MapEntry(key, stripTopLevelDirectory(removeJsExtension(value)))); - Future _moduleForServerPath( - MetadataProvider metadataProvider, String serverPath) async => - (await metadataProvider.modulePathToModule).map((key, value) => MapEntry( - stripTopLevelDirectory(key), value))[relativizePath(serverPath)]; + Future _moduleForServerPath( + MetadataProvider metadataProvider, String serverPath) async { + final modulePathToModule = await metadataProvider.modulePathToModule; + final relativePath = relativizePath(serverPath); + for (var e in modulePathToModule.entries) { + if (stripTopLevelDirectory(e.key) == relativePath) { + return e.value; + } + } + return null; + } Future _serverPathForModule( MetadataProvider metadataProvider, String module) async { @@ -80,7 +97,7 @@ class BuildRunnerRequireStrategyProvider { return stripTopLevelDirectory(path); } - String _serverPathForAppUri(String appUri) { + String? _serverPathForAppUri(String appUri) { if (appUri.startsWith('org-dartlang-app:')) { // We skip the root from which we are serving. return Uri.parse(appUri).pathSegments.skip(1).join('/'); diff --git a/dwds/lib/src/loaders/frontend_server_require.dart b/dwds/lib/src/loaders/frontend_server_require.dart index 8205dc431..4a63ea026 100644 --- a/dwds/lib/src/loaders/frontend_server_require.dart +++ b/dwds/lib/src/loaders/frontend_server_require.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'package:path/path.dart' as p; import '../debugging/metadata/provider.dart'; @@ -19,22 +17,22 @@ class FrontendServerRequireStrategyProvider { final Future> Function() _digestsProvider; final String _basePath; - RequireStrategy _requireStrategy; + late final RequireStrategy _requireStrategy = RequireStrategy( + _configuration, + _moduleProvider, + (_) => _digestsProvider(), + _moduleForServerPath, + _serverPathForModule, + _sourceMapPathForModule, + _serverPathForAppUri, + _moduleInfoForProvider, + _assetReader, + ); FrontendServerRequireStrategyProvider(this._configuration, this._assetReader, this._digestsProvider, this._basePath); - RequireStrategy get strategy => _requireStrategy ??= RequireStrategy( - _configuration, - _moduleProvider, - (_) => _digestsProvider(), - _moduleForServerPath, - _serverPathForModule, - _sourceMapPathForModule, - _serverPathForAppUri, - _moduleInfoForProvider, - _assetReader, - ); + RequireStrategy get strategy => _requireStrategy; String _removeBasePath(String path) { if (_basePath.isEmpty) return path; @@ -43,20 +41,20 @@ class FrontendServerRequireStrategyProvider { return path.startsWith(base) ? path.substring(base.length) : path; } - String _addBasePath(String serverPath) => - _basePath == null || _basePath.isEmpty - ? relativizePath(serverPath) - : '$_basePath/${relativizePath(serverPath)}'; + String _addBasePath(String serverPath) => _basePath.isEmpty + ? relativizePath(serverPath) + : '$_basePath/${relativizePath(serverPath)}'; Future> _moduleProvider( MetadataProvider metadataProvider) async => (await metadataProvider.moduleToModulePath).map((key, value) => MapEntry(key, relativizePath(removeJsExtension(value)))); - Future _moduleForServerPath( + Future _moduleForServerPath( MetadataProvider metadataProvider, String serverPath) async { final modulePathToModule = await metadataProvider.modulePathToModule; - return modulePathToModule[_removeBasePath(serverPath)]; + final relativeServerPath = _removeBasePath(serverPath); + return modulePathToModule[relativeServerPath]; } Future _serverPathForModule( @@ -67,7 +65,7 @@ class FrontendServerRequireStrategyProvider { MetadataProvider metadataProvider, String module) async => _addBasePath((await metadataProvider.moduleToSourceMap)[module] ?? ''); - String _serverPathForAppUri(String appUri) { + String? _serverPathForAppUri(String appUri) { if (appUri.startsWith('org-dartlang-app:')) { return _addBasePath(Uri.parse(appUri).path); } @@ -79,7 +77,7 @@ class FrontendServerRequireStrategyProvider { final modules = await metadataProvider.moduleToModulePath; final result = {}; for (var module in modules.keys) { - final modulePath = modules[module]; + final modulePath = modules[module]!; result[module] = ModuleInfo( // TODO: Save locations of full kernel files in ddc metadata. // Issue: https://github.com/dart-lang/sdk/issues/43684 diff --git a/dwds/lib/src/loaders/legacy.dart b/dwds/lib/src/loaders/legacy.dart index f910711b7..02e01487e 100644 --- a/dwds/lib/src/loaders/legacy.dart +++ b/dwds/lib/src/loaders/legacy.dart @@ -2,8 +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.9 - import 'package:shelf/shelf.dart'; import '../debugging/metadata/provider.dart'; @@ -61,7 +59,7 @@ class LegacyStrategy extends LoadStrategy { /// /// Will return `null` if the provided uri is not /// an app URI. - final String Function(String appUri) _serverPathForAppUri; + final String? Function(String appUri) _serverPathForAppUri; LegacyStrategy( this.reloadConfiguration, @@ -74,7 +72,7 @@ class LegacyStrategy extends LoadStrategy { ) : super(assetReader); @override - Handler get handler => (request) => null; + Handler get handler => (request) => Response.notFound(request.url); @override String get id => 'legacy'; @@ -121,5 +119,5 @@ class LegacyStrategy extends LoadStrategy { _sourceMapPathForModule(metadataProviderFor(entrypoint), module); @override - String serverPathForAppUri(String appUri) => _serverPathForAppUri(appUri); + String? serverPathForAppUri(String appUri) => _serverPathForAppUri(appUri); } diff --git a/dwds/lib/src/loaders/require.dart b/dwds/lib/src/loaders/require.dart index ab309da13..b9ba9b6fd 100644 --- a/dwds/lib/src/loaders/require.dart +++ b/dwds/lib/src/loaders/require.dart @@ -2,8 +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.9 - import 'dart:convert'; import 'package:path/path.dart' as p; @@ -20,7 +18,6 @@ import '../services/expression_compiler.dart'; /// https://localhost/base/index.html => base /// https://localhost/base => base String basePathForServerUri(String url) { - if (url == null) return null; final uri = Uri.parse(url); var base = uri.path.endsWith('.html') ? p.dirname(uri.path) : uri.path; return base = base.startsWith('/') ? base.substring(1) : base; @@ -99,7 +96,7 @@ class RequireStrategy extends LoadStrategy { /// /// /packages/path/path.ddc.js -> packages/path/path /// - final Future Function(MetadataProvider provider, String sourcePath) + final Future Function(MetadataProvider provider, String sourcePath) _moduleForServerPath; /// Returns the server path for the provided module. @@ -128,7 +125,7 @@ class RequireStrategy extends LoadStrategy { /// /// Will return `null` if the provided uri is not /// an app URI. - final String Function(String appUri) _serverPathForAppUri; + final String? Function(String appUri) _serverPathForAppUri; /// Returns a map from module id to module info. /// @@ -154,13 +151,14 @@ class RequireStrategy extends LoadStrategy { @override Handler get handler => (request) async { if (request.url.path.endsWith(_requireDigestsPath)) { + final entrypoint = request.url.queryParameters['entrypoint']; + if (entrypoint == null) return Response.notFound('${request.url}'); final metadataProvider = - metadataProviderFor(request.url.queryParameters['entrypoint']); - if (metadataProvider == null) return null; + metadataProviderFor(request.url.queryParameters['entrypoint']!); final digests = await _digestsProvider(metadataProvider); return Response.ok(json.encode(digests)); } - return null; + return Response.notFound('${request.url}'); }; @override @@ -275,7 +273,7 @@ if(!window.\$requireLoader) { } @override - Future moduleForServerPath(String entrypoint, String serverPath) { + Future moduleForServerPath(String entrypoint, String serverPath) { final metadataProvider = metadataProviderFor(entrypoint); return _moduleForServerPath(metadataProvider, serverPath); } @@ -293,7 +291,7 @@ if(!window.\$requireLoader) { } @override - String serverPathForAppUri(String appUri) => _serverPathForAppUri(appUri); + String? serverPathForAppUri(String appUri) => _serverPathForAppUri(appUri); @override Future> moduleInfoForEntrypoint(String entrypoint) => diff --git a/dwds/lib/src/loaders/strategy.dart b/dwds/lib/src/loaders/strategy.dart index c98ec8d45..ece82bf41 100644 --- a/dwds/lib/src/loaders/strategy.dart +++ b/dwds/lib/src/loaders/strategy.dart @@ -2,24 +2,17 @@ // 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.9 - import 'package:shelf/shelf.dart'; import '../debugging/metadata/provider.dart'; import '../readers/asset_reader.dart'; import '../services/expression_compiler.dart'; -LoadStrategy _globalLoadStrategy; +late LoadStrategy _globalLoadStrategy; set globalLoadStrategy(LoadStrategy strategy) => _globalLoadStrategy = strategy; -LoadStrategy get globalLoadStrategy { - if (_globalLoadStrategy == null) { - throw StateError('Global load strategy not set'); - } - return _globalLoadStrategy; -} +LoadStrategy get globalLoadStrategy => _globalLoadStrategy; abstract class LoadStrategy { final AssetReader _assetReader; @@ -92,7 +85,7 @@ abstract class LoadStrategy { /// /// /packages/path/path.ddc.js -> packages/path/path /// - Future moduleForServerPath(String entrypoint, String serverPath); + Future moduleForServerPath(String entrypoint, String serverPath); /// Returns the server path for the provided module. /// @@ -126,12 +119,17 @@ abstract class LoadStrategy { /// /// Will return `null` if the provided uri is not /// an app URI. - String serverPathForAppUri(String appUri); + String? serverPathForAppUri(String appUri); /// Returns the [MetadataProvider] for the application located at the provided /// [entrypoint]. - MetadataProvider metadataProviderFor(String entrypoint) => - _providers[entrypoint]; + MetadataProvider metadataProviderFor(String entrypoint) { + if (_providers.containsKey(entrypoint)) { + return _providers[entrypoint]!; + } else { + throw StateError('No metadata provider for $entrypoint'); + } + } /// Initializes a [MetadataProvider] for the application located at the /// provided [entrypoint].