| // Copyright 2020 The Dart Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Note: this is a copy from flutter tools, updated to work with dwds tests | 
 |  | 
 | import 'package:dwds/asset_reader.dart'; | 
 | import 'package:file/file.dart'; | 
 | import 'package:path/path.dart' as p; | 
 | import 'package:test_common/test_sdk_layout.dart'; | 
 |  | 
 | import 'asset_server.dart'; | 
 | import 'bootstrap.dart'; | 
 | import 'frontend_server_client.dart'; | 
 |  | 
 | class WebDevFS { | 
 |   WebDevFS({ | 
 |     required this.fileSystem, | 
 |     required this.hostname, | 
 |     required this.port, | 
 |     required this.projectDirectory, | 
 |     required this.packageUriMapper, | 
 |     required this.index, | 
 |     required this.soundNullSafety, | 
 |     this.urlTunneler, | 
 |     required this.sdkLayout, | 
 |   }); | 
 |  | 
 |   final FileSystem fileSystem; | 
 |   late final TestAssetServer assetServer; | 
 |   final String hostname; | 
 |   final int port; | 
 |   final Uri projectDirectory; | 
 |   final PackageUriMapper packageUriMapper; | 
 |   final String index; | 
 |   final UrlEncoder? urlTunneler; | 
 |   final bool soundNullSafety; | 
 |   final TestSdkLayout sdkLayout; | 
 |   late final Directory _savedCurrentDirectory; | 
 |  | 
 |   Future<Uri> create() async { | 
 |     _savedCurrentDirectory = fileSystem.currentDirectory; | 
 |  | 
 |     fileSystem.currentDirectory = projectDirectory.toFilePath(); | 
 |  | 
 |     assetServer = await TestAssetServer.start(sdkLayout.sdkDirectory, | 
 |         fileSystem, index, hostname, port, urlTunneler, packageUriMapper); | 
 |     return Uri.parse('http://$hostname:$port'); | 
 |   } | 
 |  | 
 |   Future<void> dispose() { | 
 |     fileSystem.currentDirectory = _savedCurrentDirectory; | 
 |     return assetServer.close(); | 
 |   } | 
 |  | 
 |   Future<UpdateFSReport> update({ | 
 |     required Uri mainUri, | 
 |     required String dillOutputPath, | 
 |     required ResidentCompiler generator, | 
 |     required List<Uri> invalidatedFiles, | 
 |   }) async { | 
 |     final mainPath = mainUri.toFilePath(); | 
 |     final outputDirectoryPath = fileSystem.file(mainPath).parent.path; | 
 |     final entryPoint = mainUri.toString(); | 
 |  | 
 |     var require = 'require.js'; | 
 |     var stackMapper = 'stack_trace_mapper.js'; | 
 |     var main = 'main.dart.js'; | 
 |     var bootstrap = 'main_module.bootstrap.js'; | 
 |  | 
 |     // If base path is not overwritten, use main's subdirectory | 
 |     // to store all files, so the paths match the requests. | 
 |     if (assetServer.basePath.isEmpty) { | 
 |       final directory = p.dirname(entryPoint); | 
 |       require = '$directory/require.js'; | 
 |       stackMapper = '$directory/stack_trace_mapper.js'; | 
 |       main = '$directory/main.dart.js'; | 
 |       bootstrap = '$directory/main_module.bootstrap.js'; | 
 |     } | 
 |  | 
 |     assetServer.writeFile( | 
 |         entryPoint, fileSystem.file(mainPath).readAsStringSync()); | 
 |     assetServer.writeFile(require, requireJS.readAsStringSync()); | 
 |     assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); | 
 |     assetServer.writeFile( | 
 |       main, | 
 |       generateBootstrapScript( | 
 |         requireUrl: 'require.js', | 
 |         mapperUrl: 'stack_trace_mapper.js', | 
 |         entrypoint: entryPoint, | 
 |       ), | 
 |     ); | 
 |     assetServer.writeFile( | 
 |       bootstrap, | 
 |       generateMainModule( | 
 |         entrypoint: entryPoint, | 
 |       ), | 
 |     ); | 
 |  | 
 |     assetServer.writeFile('main_module.digests', '{}'); | 
 |  | 
 |     var sdk = soundNullSafety ? dartSdk : dartSdkWeak; | 
 |     var sdkSourceMap = | 
 |         soundNullSafety ? dartSdkSourcemap : dartSdkSourcemapWeak; | 
 |     assetServer.writeFile('dart_sdk.js', sdk.readAsStringSync()); | 
 |     assetServer.writeFile('dart_sdk.js.map', sdkSourceMap.readAsStringSync()); | 
 |  | 
 |     generator.reset(); | 
 |     var compilerOutput = await generator.recompile( | 
 |       Uri.parse('org-dartlang-app:///$mainUri'), | 
 |       invalidatedFiles, | 
 |       outputPath: p.join(dillOutputPath, 'app.dill'), | 
 |       packageConfig: packageUriMapper.packageConfig, | 
 |     ); | 
 |     if (compilerOutput == null || compilerOutput.errorCount > 0) { | 
 |       return UpdateFSReport(success: false); | 
 |     } | 
 |  | 
 |     File codeFile; | 
 |     File manifestFile; | 
 |     File sourcemapFile; | 
 |     File metadataFile; | 
 |     List<String> modules; | 
 |     try { | 
 |       var parentDirectory = fileSystem.directory(outputDirectoryPath); | 
 |       codeFile = | 
 |           parentDirectory.childFile('${compilerOutput.outputFilename}.sources'); | 
 |       manifestFile = | 
 |           parentDirectory.childFile('${compilerOutput.outputFilename}.json'); | 
 |       sourcemapFile = | 
 |           parentDirectory.childFile('${compilerOutput.outputFilename}.map'); | 
 |       metadataFile = parentDirectory | 
 |           .childFile('${compilerOutput.outputFilename}.metadata'); | 
 |       modules = assetServer.write( | 
 |           codeFile, manifestFile, sourcemapFile, metadataFile); | 
 |     } on FileSystemException catch (err) { | 
 |       throw Exception('Failed to load recompiled sources:\n$err'); | 
 |     } | 
 |     return UpdateFSReport( | 
 |       success: true, | 
 |       syncedBytes: codeFile.lengthSync(), | 
 |       invalidatedSourcesCount: invalidatedFiles.length, | 
 |     )..invalidatedModules = modules; | 
 |   } | 
 |  | 
 |   File get requireJS => fileSystem.file(sdkLayout.requireJsPath); | 
 |   File get dartSdkWeak => fileSystem.file(sdkLayout.weakJsPath); | 
 |   File get dartSdk => fileSystem.file(sdkLayout.soundJsPath); | 
 |   File get dartSdkSourcemapWeak => fileSystem.file(sdkLayout.weakJsMapPath); | 
 |   File get dartSdkSourcemap => fileSystem.file(sdkLayout.soundJsMapPath); | 
 |   File get stackTraceMapper => fileSystem.file(sdkLayout.stackTraceMapperPath); | 
 | } | 
 |  | 
 | class UpdateFSReport { | 
 |   final bool _success; | 
 |   final int _invalidatedSourcesCount; | 
 |   final int _syncedBytes; | 
 |  | 
 |   UpdateFSReport({ | 
 |     bool success = false, | 
 |     int invalidatedSourcesCount = 0, | 
 |     int syncedBytes = 0, | 
 |   })  : _success = success, | 
 |         _invalidatedSourcesCount = invalidatedSourcesCount, | 
 |         _syncedBytes = syncedBytes; | 
 |  | 
 |   bool get success => _success; | 
 |   int get invalidatedSourcesCount => _invalidatedSourcesCount; | 
 |   int get syncedBytes => _syncedBytes; | 
 |  | 
 |   /// JavaScript modules produced by the incremental compiler in `dartdevc` | 
 |   /// mode. | 
 |   /// | 
 |   /// Only used for JavaScript compilation. | 
 |   List<String>? invalidatedModules; | 
 | } |